From 5e2e8a9188a04a85943ac598abf9627075e8d48b Mon Sep 17 00:00:00 2001 From: Maximiliano Churichi Date: Fri, 18 Aug 2023 08:52:51 +0100 Subject: [PATCH] Adds AWS KMS KeyManager support (#435) Co-authored-by: Marco Franssen Co-authored-by: kfox1111 --- .gitignore | 1 + charts/spire/README.md | 7 ++++ charts/spire/charts/spire-server/README.md | 7 ++++ .../templates/aws-kms-configmap.yaml | 10 ++++++ .../templates/aws-kms-secret.yaml | 17 ++++++++++ .../spire-server/templates/configmap.yaml | 24 ++++++++++++-- .../spire-server/templates/statefulset.yaml | 33 +++++++++++++++++++ charts/spire/charts/spire-server/values.yaml | 13 ++++++++ 8 files changed, 110 insertions(+), 2 deletions(-) create mode 100644 charts/spire/charts/spire-server/templates/aws-kms-configmap.yaml create mode 100644 charts/spire/charts/spire-server/templates/aws-kms-secret.yaml diff --git a/.gitignore b/.gitignore index 1ad54ad..beb5ec8 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,6 @@ bin/ .idea/ +.vscode/ *.swp charts/**/*.tgz .DS_Store diff --git a/charts/spire/README.md b/charts/spire/README.md index 585f3e0..a1fafe4 100644 --- a/charts/spire/README.md +++ b/charts/spire/README.md @@ -359,6 +359,13 @@ Now you can interact with the Spire agent socket from your own application. The | spire-server.ingress.tls | list | `[]` | | | spire-server.initContainers | list | `[]` | | | spire-server.jwtIssuer | string | `"https://oidc-discovery.example.org"` | The JWT issuer domain | +| spire-server.keyManager.awsKMS.accessKeyID | Optional | `""` | Access key ID for the AWS account. It's recommended to use an IAM role instead. See [here](https://docs.aws.amazon.com/eks/latest/userguide/associate-service-account-role.html) to learn how to annotate your SPIRE Server Service Account to assume an IAM role. | +| spire-server.keyManager.awsKMS.enabled | bool | `false` | | +| spire-server.keyManager.awsKMS.keyPolicy | object | `{"existingConfigMap":"","policy":""}` | Policy to use when creating keys. If no policy is specified, a default policy will be used. | +| spire-server.keyManager.awsKMS.keyPolicy.existingConfigMap | Optional | `""` | Name of a ConfigMap that has a `policy.json` file with the key policy in JSON format. | +| spire-server.keyManager.awsKMS.keyPolicy.policy | Optional | `""` | Key policy in JSON format. | +| spire-server.keyManager.awsKMS.region | string | `""` | | +| spire-server.keyManager.awsKMS.secretAccessKey | Optional | `""` | Secret access key for the AWS account. | | spire-server.keyManager.disk.enabled | bool | `true` | | | spire-server.keyManager.memory.enabled | bool | `false` | | | spire-server.livenessProbe.failureThreshold | int | `2` | Failure threshold count for livenessProbe | diff --git a/charts/spire/charts/spire-server/README.md b/charts/spire/charts/spire-server/README.md index 84cefce..84fc6ef 100644 --- a/charts/spire/charts/spire-server/README.md +++ b/charts/spire/charts/spire-server/README.md @@ -162,6 +162,13 @@ In order to run Tornjak with simple HTTP Connection only, make sure you don't cr | ingress.tls | list | `[]` | | | initContainers | list | `[]` | | | jwtIssuer | string | `"https://oidc-discovery.example.org"` | The JWT issuer domain | +| keyManager.awsKMS.accessKeyID | Optional | `""` | Access key ID for the AWS account. It's recommended to use an IAM role instead. See [here](https://docs.aws.amazon.com/eks/latest/userguide/associate-service-account-role.html) to learn how to annotate your SPIRE Server Service Account to assume an IAM role. | +| keyManager.awsKMS.enabled | bool | `false` | | +| keyManager.awsKMS.keyPolicy | object | `{"existingConfigMap":"","policy":""}` | Policy to use when creating keys. If no policy is specified, a default policy will be used. | +| keyManager.awsKMS.keyPolicy.existingConfigMap | Optional | `""` | Name of a ConfigMap that has a `policy.json` file with the key policy in JSON format. | +| keyManager.awsKMS.keyPolicy.policy | Optional | `""` | Key policy in JSON format. | +| keyManager.awsKMS.region | string | `""` | | +| keyManager.awsKMS.secretAccessKey | Optional | `""` | Secret access key for the AWS account. | | keyManager.disk.enabled | bool | `true` | | | keyManager.memory.enabled | bool | `false` | | | livenessProbe.failureThreshold | int | `2` | Failure threshold count for livenessProbe | diff --git a/charts/spire/charts/spire-server/templates/aws-kms-configmap.yaml b/charts/spire/charts/spire-server/templates/aws-kms-configmap.yaml new file mode 100644 index 0000000..a7edc7a --- /dev/null +++ b/charts/spire/charts/spire-server/templates/aws-kms-configmap.yaml @@ -0,0 +1,10 @@ +{{- if ne .Values.keyManager.awsKMS.keyPolicy.policy "" }} +apiVersion: v1 +kind: ConfigMap +metadata: + name: {{ include "spire-server.fullname" . }}-aws-kms + namespace: {{ include "spire-server.namespace" . }} +data: + policy.json: | + {{ .Values.keyManager.awsKMS.keyPolicy.policy | nindent 4 }} +{{- end }} diff --git a/charts/spire/charts/spire-server/templates/aws-kms-secret.yaml b/charts/spire/charts/spire-server/templates/aws-kms-secret.yaml new file mode 100644 index 0000000..3477dcc --- /dev/null +++ b/charts/spire/charts/spire-server/templates/aws-kms-secret.yaml @@ -0,0 +1,17 @@ +{{- $root := . }} +{{- with .Values.keyManager.awsKMS }} +{{- if or (ne .accessKeyID "") (ne .secretAccessKey "") }} +apiVersion: v1 +kind: Secret +metadata: + name: {{ include "spire-server.fullname" $root }}-aws-kms + namespace: {{ include "spire-server.namespace" $root }} +data: + {{- if ne .accessKeyID "" }} + AWS_KMS_ACCESS_KEY_ID: {{ .accessKeyID | b64enc }} + {{- end }} + {{- if ne .secretAccessKey "" }} + AWS_KMS_SECRET_ACCESS_KEY: {{ .secretAccessKey | b64enc }} + {{- end }} +{{- end }} +{{- end }} diff --git a/charts/spire/charts/spire-server/templates/configmap.yaml b/charts/spire/charts/spire-server/templates/configmap.yaml index a9e21b1..d72eae9 100644 --- a/charts/spire/charts/spire-server/templates/configmap.yaml +++ b/charts/spire/charts/spire-server/templates/configmap.yaml @@ -67,8 +67,28 @@ plugins: {{- end }} {{- end }} -{{- if gt $keyManagerUsed 1 }} -{{- fail "You can only enable a single KeyManager" }} + {{- with .Values.keyManager.awsKMS }} + {{- if eq (.enabled | toString) "true" }} + {{- $keyManagerUsed = add1 $keyManagerUsed }} + KeyManager: + - aws_kms: + plugin_data: + region: {{ .region | quote }} + key_metadata_file: "/run/spire/data/aws-kms-key-metadata" + {{- if ne .accessKeyID "" }} + access_key_id: "${AWS_KMS_ACCESS_KEY_ID}" + {{- end }} + {{- if ne .secretAccessKey "" }} + secret_access_key: "${AWS_KMS_SECRET_ACCESS_KEY}" + {{- end }} + {{- if or (ne .keyPolicy.policy "") (ne .keyPolicy.existingConfigMap "") }} + key_policy_file: "/run/spire/data/aws-kms-key-policy.json" + {{- end }} + {{- end }} + {{- end }} + +{{- if ne $keyManagerUsed 1 }} +{{- fail (printf "You have to enable exactly one Key Manager. There are %d enabled." $keyManagerUsed) }} {{- end }} Notifier: diff --git a/charts/spire/charts/spire-server/templates/statefulset.yaml b/charts/spire/charts/spire-server/templates/statefulset.yaml index 7a1fcd9..ef70c9f 100644 --- a/charts/spire/charts/spire-server/templates/statefulset.yaml +++ b/charts/spire/charts/spire-server/templates/statefulset.yaml @@ -87,6 +87,20 @@ spec: name: {{ $fullname }}-dbpw key: DBPW {{- end }} + {{- if ne .Values.keyManager.awsKMS.accessKeyID "" }} + - name: AWS_KMS_ACCESS_KEY_ID + valueFrom: + secretKeyRef: + name: {{ $fullname }}-aws-kms + key: AWS_KMS_ACCESS_KEY_ID + {{- end }} + {{- if ne .Values.keyManager.awsKMS.secretAccessKey "" }} + - name: AWS_KMS_SECRET_ACCESS_KEY + valueFrom: + secretKeyRef: + name: {{ $fullname }}-aws-kms + key: AWS_KMS_SECRET_ACCESS_KEY + {{- end }} ports: - name: grpc containerPort: 8081 @@ -136,6 +150,14 @@ spec: mountPath: /run/spire/upstream_agent readOnly: true {{ end }} + {{- with .Values.keyManager.awsKMS }} + {{- if and (eq (.enabled | toString) "true") (or (ne .keyPolicy.policy "") (ne .keyPolicy.existingConfigMap "")) }} + - name: aws-kms-key-policy + mountPath: /run/spire/data/aws-kms-key-policy.json + subPath: policy.json + readOnly: true + {{ end }} + {{ end }} {{- if gt (len .Values.extraVolumeMounts) 0 }} {{- toYaml .Values.extraVolumeMounts | nindent 12 }} {{- end }} @@ -286,6 +308,17 @@ spec: driver: {{ .Values.upstreamAuthority.spire.upstreamDriver }} readOnly: true {{- end }} + {{- with .Values.keyManager.awsKMS }} + {{- if and (eq (.enabled | toString) "true") (or (ne .keyPolicy.policy "") (ne .keyPolicy.existingConfigMap "")) }} + - name: aws-kms-key-policy + configMap: + {{- if ne .keyPolicy.policy "" }} + name: {{ $fullname }}-aws-kms + {{- else if ne .keyPolicy.existingConfigMap "" }} + name: {{ .keyPolicy.existingConfigMap }} + {{- end }} + {{- end }} + {{- end }} {{- if eq (.Values.controllerManager.enabled | toString) "true" }} - name: controller-manager-config configMap: diff --git a/charts/spire/charts/spire-server/values.yaml b/charts/spire/charts/spire-server/values.yaml index 0fff24d..3b943ba 100644 --- a/charts/spire/charts/spire-server/values.yaml +++ b/charts/spire/charts/spire-server/values.yaml @@ -180,6 +180,19 @@ keyManager: enabled: true memory: enabled: false + awsKMS: + enabled: false + region: "" + # -- Policy to use when creating keys. If no policy is specified, a default policy will be used. + keyPolicy: + # -- (Optional) Key policy in JSON format. + policy: "" + # -- (Optional) Name of a ConfigMap that has a `policy.json` file with the key policy in JSON format. + existingConfigMap: "" + # -- (Optional) Access key ID for the AWS account. It's recommended to use an IAM role instead. See [here](https://docs.aws.amazon.com/eks/latest/userguide/associate-service-account-role.html) to learn how to annotate your SPIRE Server Service Account to assume an IAM role. + accessKeyID: "" + # -- (Optional) Secret access key for the AWS account. + secretAccessKey: "" upstreamAuthority: disk: