Skip to content
This repository has been archived by the owner on Dec 15, 2022. It is now read-only.

Handle sensitive fields #77

Merged
merged 24 commits into from
Oct 7, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
db5aabf
Add ConfigStore and merge options with existing config
turkenh Sep 23, 2021
5803e0f
Extract tf fieldpath for sensitive fields
turkenh Sep 29, 2021
d4a55e1
Add utility to get values matching a field path
turkenh Sep 29, 2021
7afb124
Generate GetConnectionDetails function in Terraformed
turkenh Sep 29, 2021
a309d99
Use consistent field paths for reference and senstive fields
turkenh Sep 30, 2021
fd01603
Drop sensitive observation fields from the schema
turkenh Sep 30, 2021
2bb1634
Generate secret ref for sensitive parameters
turkenh Sep 30, 2021
017dcb1
Minor refactors and fix linter errors
turkenh Sep 30, 2021
f2c7d6f
Support for getting top level sensitive parameters
turkenh Oct 1, 2021
9b16fb5
Change fieldpath format to be compatible with API conventions
turkenh Oct 2, 2021
78de50c
Move expand wildcards to crossplane-runtime paved
turkenh Oct 2, 2021
a6ff670
Refactor - better naming and file structure
turkenh Oct 3, 2021
117ecdf
Add go mock dependency and generate mock for SecretClient
turkenh Oct 4, 2021
f132952
Update crossplane-runtime dependency for expand wildcards with fieldpath
turkenh Oct 4, 2021
ea668c0
Finalize GetSensitiveObservation/Parameters
turkenh Oct 5, 2021
a54b971
Fix minor issues like formatting and fixing license
turkenh Oct 5, 2021
6be7f62
Fix getObservation & add more unit tests
turkenh Oct 5, 2021
890de46
Merge remote-tracking branch 'upstream/main' into sensitive-fields
turkenh Oct 6, 2021
e920c43
Get connection details in controller
turkenh Oct 6, 2021
8a98213
Simplify terraformed by moving out sensitive attribute getting
turkenh Oct 6, 2021
6ada1c3
Resolve comments - renamings and cosmetic changes
turkenh Oct 6, 2021
0370a22
Always include id field in connection details
turkenh Oct 7, 2021
e808b62
Fix terraformed template, remove remnants
turkenh Oct 7, 2021
cd3c99d
Use full jsonpath in xp fieldpath
turkenh Oct 7, 2021
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,9 @@ module github.com/crossplane-contrib/terrajet
go 1.16

require (
github.com/crossplane/crossplane-runtime v0.15.1-0.20210930095326-d5661210733b
github.com/crossplane/crossplane-runtime v0.15.1-0.20211004150827-579c1833b513
github.com/fatih/camelcase v1.0.0
github.com/golang/mock v1.6.0
github.com/google/go-cmp v0.5.6
github.com/hashicorp/terraform-plugin-sdk/v2 v2.7.0
github.com/iancoleman/strcase v0.2.0
Expand Down
7 changes: 5 additions & 2 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -126,8 +126,8 @@ github.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsr
github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7DoTY=
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
github.com/creack/pty v1.1.11/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
github.com/crossplane/crossplane-runtime v0.15.1-0.20210930095326-d5661210733b h1:uT3DYSHFvWPilEMNSeR2rcuzPPVf56O0D+NJmnQFXbw=
github.com/crossplane/crossplane-runtime v0.15.1-0.20210930095326-d5661210733b/go.mod h1:gKix9Gq5kRzVe/4XOpwlFgG7OurzrYayviJxWZakhw0=
github.com/crossplane/crossplane-runtime v0.15.1-0.20211004150827-579c1833b513 h1:Sk3QurYYpy8x3c0DvTh9iGYFSv8WgdhnjCalNqNqlRI=
github.com/crossplane/crossplane-runtime v0.15.1-0.20211004150827-579c1833b513/go.mod h1:gKix9Gq5kRzVe/4XOpwlFgG7OurzrYayviJxWZakhw0=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
Expand Down Expand Up @@ -215,6 +215,8 @@ github.com/golang/mock v1.4.1/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt
github.com/golang/mock v1.4.3/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw=
github.com/golang/mock v1.4.4/go.mod h1:l3mdAwkq5BuhzHwde/uurv3sEJeZMXNpwsxVWU71h+4=
github.com/golang/mock v1.5.0/go.mod h1:CWnOUgYIOo4TcNZ0wHX3YZCqsaM1I1Jvs6v3mP3KVu8=
github.com/golang/mock v1.6.0 h1:ErTB+efbowRARo13NNdxyJji2egdxLGQhRaY+DUumQc=
github.com/golang/mock v1.6.0/go.mod h1:p6yTPP+5HYm5mzsMV8JkE6ZKdX+/wYM6Hr+LicevLPs=
github.com/golang/protobuf v1.1.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
Expand Down Expand Up @@ -882,6 +884,7 @@ golang.org/x/tools v0.0.0-20201224043029-2b0845dc783e/go.mod h1:emZCQorbCU4vsT4f
golang.org/x/tools v0.0.0-20210105154028-b0ab187a4818/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0=
golang.org/x/tools v0.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
golang.org/x/tools v0.1.2/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
golang.org/x/tools v0.1.5 h1:ouewzE6p+/VEB31YYnTbEJdi8pFqKp4P4n85vwo3DHA=
golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
Expand Down
13 changes: 13 additions & 0 deletions hack/boilerplate.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
Copyright 2021 The Crossplane Authors.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
27 changes: 27 additions & 0 deletions pkg/config/resource.go
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,28 @@ type ExternalName struct {
// given resource. Key should be the field path of the field to be referenced.
type References map[string]Reference

// Sensitive represents configurations to handle sensitive information
type Sensitive struct {
// CustomFieldPaths are the list of custom field paths to sensitive fields
// in terraform attributes.
CustomFieldPaths []string

fieldPaths map[string]string
}

// GetFieldPaths returns the fieldPaths map for Sensitive
func (s *Sensitive) GetFieldPaths() map[string]string {
return s.fieldPaths
}

// AddFieldPath adds the given tf path and xp path to the fieldPaths map.
func (s *Sensitive) AddFieldPath(tf, xp string) {
if s.fieldPaths == nil {
s.fieldPaths = make(map[string]string)
}
s.fieldPaths[tf] = xp
}

// Resource is the set of information that you can override at different steps
// of the code generation pipeline.
type Resource struct {
Expand All @@ -90,7 +112,12 @@ type Resource struct {
// ExternalName allows you to specify a custom ExternalName.
ExternalName ExternalName

// References keeps the configuration to build cross resource references
References References

// Sensitive keeps the configuration to handle sensitive information
Sensitive Sensitive

// TerraformIDFieldName is the name of the ID field in Terraform state of
// the resource. Its default is "id" and in almost all cases, you don't need
// to overwrite it.
Expand Down
17 changes: 13 additions & 4 deletions pkg/controller/external.go
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,7 @@ func (c *Connector) Connect(ctx context.Context, mg xpresource.Managed) (managed
return nil, errors.Wrap(err, errGetTerraformSetup)
}

tf, err := c.store.Workspace(ctx, tr, ts)
tf, err := c.store.Workspace(ctx, &APISecretClient{kube: c.kube}, tr, ts)
if err != nil {
return nil, errors.Wrap(err, errGetWorkspace)
}
Expand Down Expand Up @@ -160,6 +160,11 @@ func (e *external) Observe(ctx context.Context, mg xpresource.Managed) (managed.
return managed.ExternalObservation{}, errors.Wrap(err, "cannot late initialize parameters")
}

conn, err := resource.GetConnectionDetails(attr, tr.GetConnectionDetailsMapping(), tr.GetTerraformResourceIDField())
if err != nil {
return managed.ExternalObservation{}, errors.Wrap(err, "cannot get connection details")
}

// During creation (i.e. apply), Terraform already waits until resource is
// ready. So, I believe it would be safe to assume it is available if create
// step completed (i.e. resource exists).
Expand All @@ -170,11 +175,11 @@ func (e *external) Observe(ctx context.Context, mg xpresource.Managed) (managed.
return managed.ExternalObservation{}, errors.Wrap(err, errPlan)
}

// TODO(muvaf): Handle connection details.
return managed.ExternalObservation{
ResourceExists: true,
ResourceUpToDate: plan.UpToDate,
ResourceLateInitialized: lateInitedAnn || lateInitedParams,
ConnectionDetails: conn,
}, nil
}

Expand All @@ -194,11 +199,15 @@ func (e *external) Create(ctx context.Context, mg xpresource.Managed) (managed.E
if err := json.JSParser.Unmarshal(res.State.GetAttributes(), &attr); err != nil {
return managed.ExternalCreation{}, errors.Wrap(err, "cannot unmarshal state attributes")
}
// TODO(muvaf): Handle connection details.

conn, err := resource.GetConnectionDetails(attr, tr.GetConnectionDetailsMapping(), tr.GetTerraformResourceIDField())
if err != nil {
return managed.ExternalCreation{}, errors.Wrap(err, "cannot get connection details")
}

// NOTE(muvaf): Only spec and metadata changes are saved after Create call.
_, err = lateInitializeAnnotations(tr, attr, string(res.State.GetPrivateRaw()))
return managed.ExternalCreation{}, errors.Wrap(err, "cannot late initialize annotations")
return managed.ExternalCreation{ConnectionDetails: conn}, errors.Wrap(err, "cannot late initialize annotations")
}

func (e *external) Update(ctx context.Context, mg xpresource.Managed) (managed.ExternalUpdate, error) {
Expand Down
10 changes: 5 additions & 5 deletions pkg/controller/external_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -83,11 +83,11 @@ func (c WorkspaceFns) Plan(ctx context.Context) (terraform.PlanResult, error) {
}

type StoreFns struct {
WorkspaceFn func(ctx context.Context, tr resource.Terraformed, ts terraform.Setup) (*terraform.Workspace, error)
WorkspaceFn func(ctx context.Context, c resource.SecretClient, tr resource.Terraformed, ts terraform.Setup) (*terraform.Workspace, error)
}

func (s StoreFns) Workspace(ctx context.Context, tr resource.Terraformed, ts terraform.Setup) (*terraform.Workspace, error) {
return s.WorkspaceFn(ctx, tr, ts)
func (s StoreFns) Workspace(ctx context.Context, c resource.SecretClient, tr resource.Terraformed, ts terraform.Setup) (*terraform.Workspace, error) {
return s.WorkspaceFn(ctx, c, tr, ts)
}

func TestConnect(t *testing.T) {
Expand Down Expand Up @@ -132,7 +132,7 @@ func TestConnect(t *testing.T) {
return terraform.Setup{}, nil
},
store: StoreFns{
WorkspaceFn: func(_ context.Context, _ resource.Terraformed, _ terraform.Setup) (*terraform.Workspace, error) {
WorkspaceFn: func(_ context.Context, _ resource.SecretClient, _ resource.Terraformed, _ terraform.Setup) (*terraform.Workspace, error) {
return nil, errBoom
},
},
Expand All @@ -148,7 +148,7 @@ func TestConnect(t *testing.T) {
return terraform.Setup{}, nil
},
store: StoreFns{
WorkspaceFn: func(_ context.Context, _ resource.Terraformed, _ terraform.Setup) (*terraform.Workspace, error) {
WorkspaceFn: func(_ context.Context, _ resource.SecretClient, _ resource.Terraformed, _ terraform.Setup) (*terraform.Workspace, error) {
return nil, nil
},
},
Expand Down
2 changes: 1 addition & 1 deletion pkg/controller/interfaces.go
Original file line number Diff line number Diff line change
Expand Up @@ -39,5 +39,5 @@ type Workspace interface {

// Store is where we can get access to the Terraform workspace of given resource.
type Store interface {
Workspace(ctx context.Context, tr resource.Terraformed, ts terraform.Setup) (*terraform.Workspace, error)
Workspace(ctx context.Context, c resource.SecretClient, tr resource.Terraformed, ts terraform.Setup) (*terraform.Workspace, error)
}
50 changes: 50 additions & 0 deletions pkg/controller/secretclient.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
/*
Copyright 2021 The Crossplane Authors.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package controller

import (
"context"

xpv1 "github.com/crossplane/crossplane-runtime/apis/common/v1"
"github.com/pkg/errors"
v1 "k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/types"
"sigs.k8s.io/controller-runtime/pkg/client"
)

// APISecretClient is a client for getting k8s secrets
type APISecretClient struct {
turkenh marked this conversation as resolved.
Show resolved Hide resolved
kube client.Client
}

// GetSecretData gets and returns data for the referenced secret
func (a *APISecretClient) GetSecretData(ctx context.Context, ref *xpv1.SecretReference) (map[string][]byte, error) {
secret := &v1.Secret{}
if err := a.kube.Get(ctx, types.NamespacedName{Namespace: ref.Namespace, Name: ref.Name}, secret); err != nil {
return nil, err
}
return secret.Data, nil
}

// GetSecretValue gets and returns value for key of the referenced secret
func (a *APISecretClient) GetSecretValue(ctx context.Context, sel xpv1.SecretKeySelector) ([]byte, error) {
d, err := a.GetSecretData(ctx, &sel.SecretReference)
if err != nil {
return nil, errors.Wrap(err, "cannot get secret data")
}
return d[sel.Key], err
}
25 changes: 25 additions & 0 deletions pkg/generate.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
// Copyright 2021 The Crossplane Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

// +build generate

package pkg

// NOTE(muvaf): We import the tools used un go:generate targets so that we can
// track their versions using go.mod and let Go handle its installation. See
// the following link for details: https://github.com/golang/go/wiki/Modules#how-can-i-track-tool-dependencies-for-a-module

import (
_ "github.com/golang/mock/mockgen" //nolint:typecheck
)
2 changes: 1 addition & 1 deletion pkg/pipeline/crd.go
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ func (cg *CRDGenerator) Generate(cfg *config.Resource, sch *schema.Resource) err
for _, omit := range cfg.ExternalName.OmittedFields {
delete(sch.Schema, omit)
}
typeList, comments, err := tjtypes.NewBuilder(cg.pkg).Build(cfg.Kind, sch, cfg.References)
typeList, comments, err := tjtypes.NewBuilder(cg.pkg).Build(cfg, sch)
if err != nil {
return errors.Wrapf(err, "cannot build types for %s", cfg.Kind)
}
Expand Down
13 changes: 11 additions & 2 deletions pkg/pipeline/templates/terraformed.go.tmpl
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,7 @@
package {{ .CRD.APIVersion }}

import (
"github.com/crossplane/crossplane-runtime/pkg/meta"
"github.com/pkg/errors"
"github.com/pkg/errors"

"github.com/crossplane-contrib/terrajet/pkg/resource"
"github.com/crossplane-contrib/terrajet/pkg/resource/json"
Expand All @@ -23,6 +22,15 @@ func (tr *{{ .CRD.Kind }}) GetTerraformResourceIDField() string {
return "{{ .Terraform.IdentifierField }}"
}

// GetConnectionDetailsMapping for this {{ .CRD.Kind }}
func (tr *{{ .CRD.Kind }}) GetConnectionDetailsMapping() map[string]string {
{{- if .SensitiveFields }}
return map[string]string{ {{range $k, $v := .SensitiveFields}}"{{ $k }}": "{{ $v}}", {{end}} }
turkenh marked this conversation as resolved.
Show resolved Hide resolved
{{- else }}
return nil
{{- end }}
}

// GetObservation of this {{ .CRD.Kind }}
func (tr *{{ .CRD.Kind }}) GetObservation() (map[string]interface{}, error) {
o, err := json.TFParser.Marshal(tr.Status.AtProvider)
Expand Down Expand Up @@ -75,3 +83,4 @@ func (tr *{{ .CRD.Kind }}) LateInitialize(attrs []byte) (bool, error) {
resource.WithZeroElemPtrFilter(resource.CNameWildcard))
return li.LateInitialize(&tr.Spec.ForProvider, params)
}

1 change: 1 addition & 0 deletions pkg/pipeline/terraformed.go
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,7 @@ func (tg *TerraformedGenerator) Generate(c *config.Resource) error {
"IdentifierField": c.TerraformIDFieldName,
"ResourceType": c.TerraformResourceType,
},
"SensitiveFields": c.Sensitive.GetFieldPaths(),
}

filePath := filepath.Join(tg.LocalDirectoryPath, fmt.Sprintf("zz_%s_terraformed.go", strings.ToLower(c.Kind)))
Expand Down
80 changes: 80 additions & 0 deletions pkg/resource/fake/mocks/mock.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading