Merge "Adding a place for external secrets to be stored on site level"

This commit is contained in:
Zuul 2021-05-08 02:24:13 +00:00 committed by Gerrit Code Review
commit a2b70338c0
27 changed files with 94 additions and 54 deletions

View File

@ -12,7 +12,7 @@ Airshipctl uses kustomize along with different krm-functions that extend its fun
Replacement krm-function that is needed to avoid duplication of data in documents Replacement krm-function that is needed to avoid duplication of data in documents
Templater krm-function that is needed to produce new yaml documents based on the provided parameters. Templater krm-function that is needed to produce new yaml documents based on the provided parameters.
There is a standard catalog of [krm-functions](https://github.com/GoogleContainerTools/kpt-functions-catalog). There is a standard catalog of [krm-functions](https://github.com/GoogleContainerTools/kpt-functions-catalog).
It includes the standard krm-function: `gcr.io/kpt-functions/sops` that can be used to perform decryption and encryption right in kustomize. Please refer to the example configurations that can be used to encrypt and decrypt the set of [existing yamls](https://github.com/GoogleContainerTools/kpt-functions-catalog/blob/master/examples/sops/local-configs/function.yaml). It includes the standard krm-function: `gcr.io/kpt-fn-contrib/sops` that can be used to perform decryption and encryption right in kustomize. Please refer to the example configurations that can be used to encrypt and decrypt the set of [existing yamls](https://github.com/GoogleContainerTools/kpt-functions-catalog/blob/master/examples/contrib/sops/function.yaml).
Please note that to make that krm-function work its necessary to provide the following ENV variables: Please note that to make that krm-function work its necessary to provide the following ENV variables:
@ -57,9 +57,11 @@ In order to implement all that functionality it was necessary to introduce a new
Krm-functions accept a set of yamls and config as input and return a modified set of yamls. Krm-functions accept a set of yamls and config as input and return a modified set of yamls.
GenericContainer executor may just output it to stdout. Or it may store it as `kpt fn sink` does. GenericContainer executor may just output it to stdout. Or it may store it as `kpt fn sink` does.
In particular were using the second option to store our generated and encrypted yamls to the specific place from which other manifests will take [that file](manifests/site/test-site/target/generator/results/generated/secrets.yaml). In particular were using the second option to store our generated and encrypted yamls to the specific place from which other manifests will take [that file](manifests/site/test-site/target/encrypted/results/generated/secrets.yaml).
As its possible to see [generator kustomization](manifests/site/test-site/target/generator/results/kustomization.yaml) performs decryption using sops krm-function. There is a way to provide external secrets, that shouldn't be generated. That secrets must be stored in encrypted way in [another file](manifests/site/test-site/target/encrypted/results/imported/secrets.yaml).
As its possible to see [encrypted kustomization](manifests/site/test-site/target/encrypted/results/kustomization.yaml) performs decryption using sops krm-function.
# Step-by-step Operator instructions # Step-by-step Operator instructions
@ -130,7 +132,7 @@ We hope that it wont be necessary to do these actions manually, because airsh
sops <file name> sops <file name>
``` ```
This will decrypt the file and will open it in the editor. It will be possible to perform needed modifications. Once finished just close the editor and sops will encrypt the modified document and put it back. This may be a really-really useful command for some users and very simple at the same time. This will decrypt the file and will open it in the editor. It will be possible to perform needed modifications. Once finished just close the editor and sops will encrypt the modified document and put it back. This may be a really-really useful command for some users and very simple at the same time. This approach may be used in order to modify [imported secrets](manifests/site/test-site/target/encrypted/results/imported/secrets.yaml).
## Generation/Regeneration and encryption of secrets in manifests ## Generation/Regeneration and encryption of secrets in manifests
@ -167,8 +169,6 @@ This config file defines the following structure of VariableCatalogue:
labels: labels:
airshipit.org/deploy-k8s: "false" airshipit.org/deploy-k8s: "false"
name: generated-secrets name: generated-secrets
annotations:
config.kubernetes.io/path: secrets.yaml
ephemeralClusterCa:... ephemeralClusterCa:...
ephemeralKubeconfig:.. ephemeralKubeconfig:..
targetClusterCa:... targetClusterCa:...
@ -180,6 +180,8 @@ Please pay attention to the annotation `config.kubernetes.io/path` - it defines
When this template is executed it generates keys/certs/passwords and renders them as a Variable catalog with the name `generated-secrets`. When this template is executed it generates keys/certs/passwords and renders them as a Variable catalog with the name `generated-secrets`.
Please pay attention that the special annotation `config.kubernetes.io/path` is getting added in the fileplacement transformer - it defines the name of the file where this document will be stored by phase. Its possible to define several VariableCatalogues with unique names of files (it even may contain directories).
Now if we refer back to the Phase descritption well see that its type is GenericContainer with the name `encrypter`. Now if we refer back to the Phase descritption well see that its type is GenericContainer with the name `encrypter`.
The definition of that executor is the following: The definition of that executor is the following:
@ -192,7 +194,7 @@ metadata:
labels: labels:
airshipit.org/deploy-k8s: "false" airshipit.org/deploy-k8s: "false"
spec: spec:
sinkOutputDir: "target/generator/results/generated" sinkOutputDir: "target/generator/results"
image: gcr.io/kpt-fn-contrib/sops:v0.1.0 image: gcr.io/kpt-fn-contrib/sops:v0.1.0
envVars: envVars:
- SOPS_IMPORT_PGP - SOPS_IMPORT_PGP
@ -205,28 +207,29 @@ config: |
unencrypted-regex: '^(kind|apiVersion|group|metadata)$' unencrypted-regex: '^(kind|apiVersion|group|metadata)$'
``` ```
Basically this executor accepts the bundle, runs krm-function `gcr.io/kpt-fn-contrib/sops:v0.1.0` with configuration from `config` field and stores the result to the directory `target/generator/results/generated` based on the filenames/hierarchy defined by annotation `config.kubernetes.io/path`. Sops krm-function in its turn encrypts documents and that means that `target/generator/results/generated` will contain encrypted yamls. To make that work the user will need just to specify 2 environment variables: Basically this executor accepts the bundle, runs krm-function `gcr.io/kpt-fn-contrib/sops:v0.1.0` with configuration from `config` field and stores the result to the directory `target/generator/results` based on the filenames/hierarchy defined by annotation `config.kubernetes.io/path`. Sops krm-function in its turn encrypts documents and that means that `target/generator/results/` will contain encrypted yamls. To make that work the user will need just to specify 2 environment variables:
- `SOPS_IMPORT_PGP` - `SOPS_IMPORT_PGP`
- `SOPS_PGP_FP` - `SOPS_PGP_FP`
Possible option how to encrypt `externally provided secrets` Possible option how to encrypt `externally provided secrets`:
First of all - its possible to make as many phases as needed, each phase will cover its separate procedure, e.g.: change of LDAP credentials, update some external passwords. This feature is already in place - it's possible to update improted secrtets manually.
Futher possible improvements are to make as many phases as needed, each phase will cover its separate procedure, e.g.: change of LDAP credentials, update some external passwords.
The only limitation is that each procedure has to have its own VariableCatalogues - that just allows not to decrypte/re-encrypt values from all VariableCatalogues. The only limitation is that each procedure has to have its own VariableCatalogues - that just allows not to decrypte/re-encrypt values from all VariableCatalogues.
For `Externally provided secrets` we should use some unencrypted VariableCatalogue as a resource instead of templater. The encryption executor configuration will look the same. We should use some unencrypted VariableCatalogue as a resource and be able to encrypt that and put to imported secrets.
Moreover, its possible to combine several secret sources in 1 phase, e.g. if we need to encrypt generated and externally provided secrets, just create another directory with kustomization, and put there different resources: Moreover, its possible to combine several secret sources in 1 phase, e.g. if we need to encrypt generated and externally provided secrets, just create another directory with kustomization, and put there different resources:
1. Local files with `externally provided secrets` in form of unencrypted variable catalogues 1. Local files with `externally provided secrets` in form of unencrypted variable catalogues
2. Directory `target/generator`. 2. Directory `target/encrypted`.
Update phases documentEntryPoint with the new path to the created directory. Now when you run the phase - all these files along with newly generated secrets will be encrypted. Update phases documentEntryPoint with the new path to the created directory. Now when you run the phase - all these files along with newly generated secrets will be encrypted.
## Decryption of secrets and using them ## Decryption of secrets and using them
The current implementation of manifests doesnt require explicit decryption of files. All secrets are decrypted on the spot. Here are the details of how it was achieved: The current implementation of manifests doesnt require explicit decryption of files. All secrets are decrypted on the spot. Here are the details of how it was achieved:
All encrypted documents are listed in the [following kustomization file](https://github.com/airshipit/airshipctl/blob/master/manifests/site/test-site/target/generator/results/kustomization.yaml). All encrypted documents are listed in the [following kustomization file](https://github.com/airshipit/airshipctl/blob/master/manifests/site/test-site/target/encrypted/results/kustomization.yaml).
This kustomization file performs decryption by invoking `decrypt-secrets` transformer, that is just a sops krm-function configuration that decrypts all encrypted documents. This kustomization file performs decryption by invoking `decrypt-secrets` transformer, that is just a sops krm-function configuration that decrypts all encrypted documents.
Note: we made a special kustomization for decrypt-secrets configuration just to be able to modify it a bit depending on the environment variable `TOLERATE_DECRYPTION_FAILURES` value. If its true were adding parameter `cmd-tolerate-failures: true` to sops configuration. Note: we made a special kustomization for decrypt-secrets configuration just to be able to modify it a bit depending on the environment variable `TOLERATE_DECRYPTION_FAILURES` value. If its true were adding parameter `cmd-tolerate-failures: true` to sops configuration.

View File

@ -14,7 +14,7 @@ mark it with `deploy-k8s: true` annotation.
Make a copy of this folder to the appropraite site for which secrets has to Make a copy of this folder to the appropraite site for which secrets has to
be generated and then edit the [secret-generation.yaml](secret-generation.yaml) be generated and then edit the [secret-generation.yaml](secret-generation.yaml)
with the required secret generation details. with the required secret generation details.
For example refer to [generator](../../site/test-site/target/generator/) folder. For example refer to [generator](../../site/test-site/target/encrypted/) folder.
Once the secret definitions are in place in the site manifests, we can Once the secret definitions are in place in the site manifests, we can
add a new phase to generate secrets pointing to the folder in site manifests. add a new phase to generate secrets pointing to the folder in site manifests.
@ -30,7 +30,7 @@ config:
apiVersion: airshipit.org/v1alpha1 apiVersion: airshipit.org/v1alpha1
kind: GenericContainer kind: GenericContainer
name: encrypter name: encrypter
documentEntryPoint: target/generator documentEntryPoint: target/encrypted
``` ```
The executorRef is of `kind: GenericContainer` and should also have the The executorRef is of `kind: GenericContainer` and should also have the
@ -44,7 +44,7 @@ metadata:
name: encrypter name: encrypter
labels: labels:
airshipit.org/deploy-k8s: "false" airshipit.org/deploy-k8s: "false"
kustomizeSinkOutputDir: "target/generator/results/generated" kustomizeSinkOutputDir: "target/encrypted/results/generated"
spec: spec:
container: container:
image: gcr.io/kpt-fn-contrib/sops:v0.1.0 image: gcr.io/kpt-fn-contrib/sops:v0.1.0
@ -98,7 +98,7 @@ metadata:
name: encrypter name: encrypter
labels: labels:
airshipit.org/deploy-k8s: "false" airshipit.org/deploy-k8s: "false"
kustomizeSinkOutputDir: "target/generator/results/generated" kustomizeSinkOutputDir: "target/encrypted/results/generated"
spec: spec:
container: container:
image: quay.io/airshipit/templater:v2 image: quay.io/airshipit/templater:v2
@ -109,7 +109,7 @@ config: |
## Decrypt to read the secrets ## Decrypt to read the secrets
To decrypt the secrets for readability purposes run the kustomize build To decrypt the secrets for readability purposes run the kustomize build
command on the generated secrets folder with the [kustomization.yaml](../../site/test-site/target/generator/results/kustomization.yaml) and [decrypt-secrets.yaml](../../site/test-site/target/generator/results/decrypt-secrets.yaml) command on the generated secrets folder with the [kustomization.yaml](../../site/test-site/target/encrypted/results/kustomization.yaml) and [decrypt-secrets.yaml](../../site/test-site/target/encrypted/results/decrypt-secrets.yaml)
files in place in the same folder. files in place in the same folder.
Kustomize command to decrypt: Kustomize command to decrypt:

View File

@ -1,2 +0,0 @@
resources:
- smp.yaml

View File

@ -1,11 +0,0 @@
apiVersion: builtin
kind: PatchStrategicMergeTransformer
metadata:
name: smp-hwparofile
patches: |-
---
apiVersion: airshipit.org/v1alpha1
kind: VariableCatalogue
metadata:
name: hardwareprofile-example
$patch: delete

View File

@ -1,2 +0,0 @@
resources:
- smp.yaml

View File

@ -55,7 +55,7 @@ metadata:
airshipit.org/deploy-k8s: "false" airshipit.org/deploy-k8s: "false"
spec: spec:
type: krm type: krm
sinkOutputDir: "target/generator/results/generated" sinkOutputDir: "target/encrypted/results"
image: gcr.io/kpt-fn-contrib/sops:v0.1.0 image: gcr.io/kpt-fn-contrib/sops:v0.1.0
envVars: envVars:
- SOPS_IMPORT_PGP - SOPS_IMPORT_PGP

View File

@ -224,7 +224,7 @@ config:
apiVersion: airshipit.org/v1alpha1 apiVersion: airshipit.org/v1alpha1
kind: GenericContainer kind: GenericContainer
name: encrypter name: encrypter
documentEntryPoint: target/generator documentEntryPoint: target/encrypted/generator
--- ---
apiVersion: airshipit.org/v1alpha1 apiVersion: airshipit.org/v1alpha1
kind: Phase kind: Phase
@ -235,7 +235,7 @@ config:
apiVersion: airshipit.org/v1alpha1 apiVersion: airshipit.org/v1alpha1
kind: GenericContainer kind: GenericContainer
name: decrypter name: decrypter
documentEntryPoint: target/generator/results documentEntryPoint: target/encrypted/results
--- ---
apiVersion: airshipit.org/v1alpha1 apiVersion: airshipit.org/v1alpha1
kind: Phase kind: Phase
@ -246,7 +246,7 @@ config:
apiVersion: airshipit.org/v1alpha1 apiVersion: airshipit.org/v1alpha1
kind: GenericContainer kind: GenericContainer
name: encrypter name: encrypter
documentEntryPoint: target/generator/results documentEntryPoint: target/encrypted/results
--- ---
apiVersion: airshipit.org/v1alpha1 apiVersion: airshipit.org/v1alpha1
kind: Phase kind: Phase

View File

@ -4,7 +4,7 @@ kind: Kustomization
resources: resources:
- ../../../../type/gating/shared/catalogues - ../../../../type/gating/shared/catalogues
- hosts.yaml - hosts.yaml
- ../generator/results - ../encrypted/results
patchesStrategicMerge: patchesStrategicMerge:
- versions-airshipctl.yaml - versions-airshipctl.yaml

View File

@ -0,0 +1,2 @@
resources:
- ../../../../../../type/gating/target/generator/

View File

@ -0,0 +1,2 @@
resources:
- ../../../../../../type/gating/target/generator/fileplacement

View File

@ -0,0 +1,2 @@
resources:
- ../../../../../../type/gating/target/importer/fileplacement

View File

@ -0,0 +1,33 @@
apiVersion: airshipit.org/v1alpha1
kind: VariableCatalogue
metadata:
labels:
airshipit.org/deploy-k8s: "false"
name: imported-secrets
dummySecrets: ENC[AES256_GCM,data:wksRVJ1SVPJ8wIcnVA00,iv:wt6FmbfFh+31g/pBcTTlerrwHoUoF8Hv3Cw9q//bSWs=,tag:PTidwzah8PiqAtGnYSa1+w==,type:str]
sops:
kms: []
gcp_kms: []
azure_kv: []
hc_vault: []
age: []
lastmodified: "2021-04-14T16:28:51Z"
mac: ENC[AES256_GCM,data:sHiCLqMg7TU4eXgThM5q+0Jq67uWoDunk1AbTqXOCKUA9gBHtKflgfgxLvhz8am7pOGf/i8UikFJx5Gb/TiAyf4GGKsfFbKDXc+JwnMYbKoibRJ1cxfRKgcwXdCohcb1g4bSiX2iHmEaVKHlF5ydvfn1OMWR5hQpavSgrb8JemA=,iv:3fg3EgYQjaLCluTL9Yu1axyucAOWwH0SREQMyvMeuak=,tag:lhA5n06vB2adYiv+cGskuA==,type:str]
pgp:
- created_at: "2021-04-14T16:28:50Z"
enc: |-
-----BEGIN PGP MESSAGE-----
wcBMAyUpShfNkFB/AQgAXrMxHATnkcDVixx+LpHMRFZeEnJsnKhFMkYIC+fhtpJD
V73hTSSBhbFTlko81oBohS151qNrS1qtVbOhS5anlTOrgZnZ2Fmwt7YIxc68xbhO
1fX8XbDAU2NmtWSdmc9sFLCrnpKakHuJfq6PMii8Cga126K7Smt62XuyFWw7r1Z+
gyJXgIE2c1GNZmgKhhPgcVBZuyGr6x1Ml4t6qPqMTn1af64T4co+ujI0n1n3dXie
p/xCPD2QrI1DSMZgvJzPf8SVUD9jh70LUGJR4fY4U1kTazs/K1JwrPLSH/rWStUA
+MNtXkitYzQa4KH4Zr+3rEH6pC8ezgtntT99Wkj8g9LmAcyF+naWCh0Akaui+UNJ
21DterDBlRsuJWUgFB54Kw+rSh7T1E4XbZzGQrb86EtCx9+gtPaRJoGYBi98wWAR
MORhPC2ylZX46XzMj9DTfMN44rvitTcA
=mdwS
-----END PGP MESSAGE-----
fp: FBC7B9E2A4F9289AC0C1D4843D16CEE4A27381B4
unencrypted_regex: ^(kind|apiVersion|group|metadata)$
version: 3.7.1

View File

@ -0,0 +1,8 @@
resources:
- generated/secrets.yaml
- imported/secrets.yaml
transformers:
- decrypt-secrets
- ../generator/overrideplacement
- ../importer/overrideplacement

View File

@ -1,2 +0,0 @@
resources:
- ../../../../../type/gating/target/generator/

View File

@ -1,2 +0,0 @@
resources:
- ../../../../../type/gating/target/generator/fileplacement

View File

@ -1,6 +0,0 @@
resources:
- generated/secrets.yaml
transformers:
- decrypt-secrets
- ../overrideplacement

View File

@ -1,11 +1,11 @@
apiVersion: builtin apiVersion: builtin
kind: PatchTransformer kind: PatchTransformer
metadata: metadata:
name: filnames-patch name: generated-filnames-patch
patch: | patch: |
apiVersion: airshipit.org/v1alpha1 apiVersion: airshipit.org/v1alpha1
kind: VariableCatalogue kind: VariableCatalogue
metadata: metadata:
name: generated-secrets name: generated-secrets
annotations: annotations:
config.kubernetes.io/path: secrets.yaml config.kubernetes.io/path: generated/secrets.yaml

View File

@ -0,0 +1,2 @@
resources:
- secret-cleanup.yaml

View File

@ -1,11 +1,11 @@
apiVersion: builtin apiVersion: builtin
kind: PatchStrategicMergeTransformer kind: PatchStrategicMergeTransformer
metadata: metadata:
name: smp-hgc name: smp_cleanup_imported
patches: |- patches: |-
--- ---
apiVersion: airshipit.org/v1alpha1 apiVersion: airshipit.org/v1alpha1
kind: VariableCatalogue kind: VariableCatalogue
metadata: metadata:
name: host-generation-catalogue name: imported-secrets
$patch: delete $patch: delete

View File

@ -0,0 +1,11 @@
apiVersion: builtin
kind: PatchTransformer
metadata:
name: imported-filnames-patch
patch: |
apiVersion: airshipit.org/v1alpha1
kind: VariableCatalogue
metadata:
name: imported-secrets
annotations:
config.kubernetes.io/path: imported/secrets.yaml

View File

@ -0,0 +1,2 @@
resources:
- filepaths.yaml

View File

@ -48,13 +48,13 @@ if [[ -z "${decrypted1}" ]]; then
fi fi
#make sure that generated file has right FP #make sure that generated file has right FP
grep "${SOPS_PGP_FP}" "${AIRSHIP_CONFIG_MANIFEST_DIRECTORY}/$(basename ${AIRSHIP_CONFIG_PHASE_REPO_URL})/manifests/site/$SITE/target/generator/results/generated/secrets.yaml" grep "${SOPS_PGP_FP}" "${AIRSHIP_CONFIG_MANIFEST_DIRECTORY}/$(basename ${AIRSHIP_CONFIG_PHASE_REPO_URL})/manifests/site/$SITE/target/encrypted/results/generated/secrets.yaml"
#set new FP and reencrypt #set new FP and reencrypt
export SOPS_PGP_FP=${SOPS_PGP_FP_REENCRYPT} export SOPS_PGP_FP=${SOPS_PGP_FP_REENCRYPT}
airshipctl phase run secret-reencrypt airshipctl phase run secret-reencrypt
#make sure that generated file has right FP #make sure that generated file has right FP
grep "${SOPS_PGP_FP}" "${AIRSHIP_CONFIG_MANIFEST_DIRECTORY}/$(basename ${AIRSHIP_CONFIG_PHASE_REPO_URL})/manifests/site/$SITE/target/generator/results/generated/secrets.yaml" grep "${SOPS_PGP_FP}" "${AIRSHIP_CONFIG_MANIFEST_DIRECTORY}/$(basename ${AIRSHIP_CONFIG_PHASE_REPO_URL})/manifests/site/$SITE/target/encrypted/results/generated/secrets.yaml"
#make sure that decrypted valus stay the same #make sure that decrypted valus stay the same
decrypted2=$(airshipctl phase run secret-show) decrypted2=$(airshipctl phase run secret-show)