Skip to content

Commit

Permalink
update code comments and kms decryption docs
Browse files Browse the repository at this point in the history
Signed-off-by: Sanskar Jaiswal <[email protected]>
  • Loading branch information
Sanskar Jaiswal committed May 4, 2022
1 parent 4a25078 commit 6bfdba4
Show file tree
Hide file tree
Showing 4 changed files with 68 additions and 19 deletions.
6 changes: 3 additions & 3 deletions controllers/kustomization_decryptor.go
Original file line number Diff line number Diff line change
Expand Up @@ -129,8 +129,8 @@ type KustomizeDecryptor struct {
// vaultToken is the Hashicorp Vault token used to authenticate towards
// any Vault server.
vaultToken string
// awsCredsProvider is the AWS credentials provider object used to authenticate towards
// any AWS KMS.
// awsCredsProvider is the AWS credentials provider object used to authenticate
// towards any AWS KMS.
awsCredsProvider *awskms.CredsProvider
// azureToken is the Azure credential token used to authenticate towards
// any Azure Key Vault.
Expand Down Expand Up @@ -225,7 +225,7 @@ func (d *KustomizeDecryptor) ImportKeys(ctx context.Context) error {
}
case filepath.Ext(DecryptionAWSKmsFile):
if name == DecryptionAWSKmsFile {
if d.awsCredsProvider, err = awskms.LoadAwsKmsCredsProviderFromYaml(value); err != nil {
if d.awsCredsProvider, err = awskms.LoadCredsProviderFromYaml(value); err != nil {
return fmt.Errorf("failed to import '%s' data from %s decryption Secret '%s': %w", name, provider, secretName, err)
}
}
Expand Down
34 changes: 34 additions & 0 deletions docs/spec/v1beta2/kustomization.md
Original file line number Diff line number Diff line change
Expand Up @@ -1255,6 +1255,40 @@ kubectl -n flux-system annotate serviceaccount kustomize-controller \
eks.amazonaws.com/role-arn='arn:aws:iam::<ACCOUNT_ID>:role/<KMS-ROLE-NAME>'
```

Furthermore, you can also use the usual [enviornment variables used for specifying AWS
credentials](https://docs.aws.amazon.com/cli/latest/userguide/cli-configure-envvars.html#envvars-list)
, by patching the kustomize-controller deployment:

```yaml
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: kustomize-controller
namespace: flux-system
spec:
template:
spec:
containers:
- name: manager
env:
- name: AWS_ACCESS_KEY_ID
valueFrom:
secretKeyRef:
name: aws-creds
key: awsAccessKeyID
- name: AWS_SECRET_ACCESS_KEY
valueFrom:
secretKeyRef:
name: aws-creds
key: awsSecretAccessKey
- name: AWS_SESSION_TOKEN
valueFrom:
secretKeyRef:
name: aws-creds
key: awsSessionToken
```

In addition to this, the
[general SOPS documentation around KMS AWS applies](https://github.com/mozilla/sops#27kms-aws-profiles),
allowing you to specify e.g. a `SOPS_KMS_ARN` environment variable.
Expand Down
45 changes: 30 additions & 15 deletions internal/sops/awskms/keysource.go
Original file line number Diff line number Diff line change
Expand Up @@ -35,13 +35,18 @@ import (
)

const (
arnRegex = `^arn:aws[\w-]*:kms:(.+):[0-9]+:(key|alias)/.+$`
stsSessionRegex = "[^a-zA-Z0-9=,.@-]+"
// valid ARN example: arn:aws:kms:us-west-2:107501996527:key/612d5f0p-p1l3-45e6-aca6-a5b005693a48
arnRegex = `^arn:aws[\w-]*:kms:(.+):[0-9]+:(key|alias)/.+$`
// valid STS session examples: john_s, sops@42WQm042
stsSessionRegex = "[^a-zA-Z0-9=,.@-_]+"
// kmsTTL is the duration after which a MasterKey requires rotation.
kmsTTL = time.Hour * 24 * 30 * 6
)

// MasterKey is a AWS KMS key used to encrypt and decrypt sops' data key.
// MasterKey is an AWS KMS key used to encrypt and decrypt sops' data key.
// Adapted from: https://github.com/mozilla/sops/blob/v3.7.2/kms/keysource.go#L39
// Modified to accept custom static credentials as opposed to using env vars by default
// and use aws-sdk-go-v2 instead of aws-sdk-go being used in upstream.
type MasterKey struct {
Arn string
Role string
Expand All @@ -64,7 +69,7 @@ type CredsProvider struct {
credsProvider aws.CredentialsProvider
}

// NewCredsProvider returns a Creds object with the provided aws.CredentialsProvider
// NewCredsProvider returns a Creds object with the provided aws.CredentialsProvider.
func NewCredsProvider(cp aws.CredentialsProvider) *CredsProvider {
return &CredsProvider{
credsProvider: cp,
Expand All @@ -76,9 +81,9 @@ func (c CredsProvider) ApplyToMasterKey(key *MasterKey) {
key.credentialsProvider = c.credsProvider
}

// LoadAwsKmsCredsProviderFromYaml parses the given yaml returns a CredsProvider object
// LoadCredsProviderFromYaml parses the given YAML returns a CredsProvider object
// which contains the credentials provider used for authenticating towards AWS KMS.
func LoadAwsKmsCredsProviderFromYaml(b []byte) (*CredsProvider, error) {
func LoadCredsProviderFromYaml(b []byte) (*CredsProvider, error) {
credInfo := struct {
AccessKeyID string `json:"aws_access_key_id"`
SecretAccessKey string `json:"aws_secret_access_key"`
Expand All @@ -93,17 +98,18 @@ func LoadAwsKmsCredsProviderFromYaml(b []byte) (*CredsProvider, error) {
}, nil
}

// EncryptedDataKey returns the encrypted data key this master key holds
// EncryptedDataKey returns the encrypted data key this master key holds.
func (key *MasterKey) EncryptedDataKey() []byte {
return []byte(key.EncryptedKey)
}

// SetEncryptedDataKey sets the encrypted data key for this master key
// SetEncryptedDataKey sets the encrypted data key for this master key.
func (key *MasterKey) SetEncryptedDataKey(enc []byte) {
key.EncryptedKey = string(enc)
}

// Encrypt takes a sops data key, encrypts it with KMS and stores the result in the EncryptedKey field
// Encrypt takes a sops data key, encrypts it with KMS and stores the result
// in the EncryptedKey field.
func (key *MasterKey) Encrypt(dataKey []byte) error {
cfg, err := key.createKMSConfig()
if err != nil {
Expand All @@ -122,7 +128,8 @@ func (key *MasterKey) Encrypt(dataKey []byte) error {
return nil
}

// EncryptIfNeeded encrypts the provided sops' data key and encrypts it if it hasn't been encrypted yet
// EncryptIfNeeded encrypts the provided sops' data key and encrypts it, if it
// has not been encrypted yet.
func (key *MasterKey) EncryptIfNeeded(dataKey []byte) error {
if key.EncryptedKey == "" {
return key.Encrypt(dataKey)
Expand Down Expand Up @@ -158,12 +165,13 @@ func (key *MasterKey) NeedsRotation() bool {
return time.Since(key.CreationDate) > (time.Hour * 24 * 30 * 6)
}

// ToString converts the key to a string representation
// ToString converts the key to a string representation.
func (key *MasterKey) ToString() string {
return key.Arn
}

// NewMasterKey creates a new MasterKey from an ARN, role and context, setting the creation date to the current date
// NewMasterKey creates a new MasterKey from an ARN, role and context, setting the
// creation date to the current date.
func NewMasterKey(arn string, role string, context map[string]string) *MasterKey {
return &MasterKey{
Arn: arn,
Expand All @@ -173,7 +181,8 @@ func NewMasterKey(arn string, role string, context map[string]string) *MasterKey
}
}

// NewMasterKeyFromArn takes an ARN string and returns a new MasterKey for that ARN
// NewMasterKeyFromArn takes an ARN string and returns a new MasterKey for that
// ARN.
func NewMasterKeyFromArn(arn string, context map[string]string, awsProfile string) *MasterKey {
k := &MasterKey{}
arn = strings.Replace(arn, " ", "", -1)
Expand All @@ -189,11 +198,15 @@ func NewMasterKeyFromArn(arn string, context map[string]string, awsProfile strin
return k
}

// createKMSConfig returns a Config configured with the appropriate credentials.
func (key MasterKey) createKMSConfig() (*aws.Config, error) {
// Uses the credentialsProvider if present, otherwise default to reading credentials
// from the enviornment.
cfg, err := config.LoadDefaultConfig(context.TODO(), func(lo *config.LoadOptions) error {
if key.credentialsProvider != nil {
lo.Credentials = key.credentialsProvider
}
// Set the epResolver, if present. Used ONLY for tests.
if key.epResolver != nil {
lo.EndpointResolver = key.epResolver
}
Expand All @@ -209,6 +222,8 @@ func (key MasterKey) createKMSConfig() (*aws.Config, error) {
return &cfg, nil
}

// createSTSConfig uses AWS STS to assume a role and returns a Config configured
// with that role's credentials.
func (key MasterKey) createSTSConfig(config *aws.Config) (*aws.Config, error) {
hostname, err := os.Hostname()
if err != nil {
Expand All @@ -223,7 +238,7 @@ func (key MasterKey) createSTSConfig(config *aws.Config) (*aws.Config, error) {

client := sts.NewFromConfig(*config)
input := &sts.AssumeRoleInput{
RoleArn: &key.Arn,
RoleArn: &key.Role,
RoleSessionName: &name,
}
out, err := client.AssumeRole(context.TODO(), input)
Expand All @@ -236,7 +251,7 @@ func (key MasterKey) createSTSConfig(config *aws.Config) (*aws.Config, error) {
return config, nil
}

// ToMap converts the MasterKey to a map for serialization purposes
// ToMap converts the MasterKey to a map for serialization purposes.
func (key MasterKey) ToMap() map[string]interface{} {
out := make(map[string]interface{})
out["arn"] = key.Arn
Expand Down
2 changes: 1 addition & 1 deletion internal/sops/awskms/keysource_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -276,7 +276,7 @@ aws_access_key_id: test-id
aws_secret_access_key: test-secret
aws_session_token: test-token
`)
credsProvider, err := LoadAwsKmsCredsProviderFromYaml(credsYaml)
credsProvider, err := LoadCredsProviderFromYaml(credsYaml)
g.Expect(err).ToNot(HaveOccurred())

creds, err := credsProvider.credsProvider.Retrieve(context.TODO())
Expand Down

0 comments on commit 6bfdba4

Please sign in to comment.