diff --git a/simple-sops/.env.age b/simple-sops/.env.age new file mode 100644 index 0000000..a7f957e --- /dev/null +++ b/simple-sops/.env.age @@ -0,0 +1,3 @@ +# INSECURE !!! +# public key: age17putd49qeggegt8nlwvtruq8fut5lsny3894e0vta9mpn6udvpvs8809zy +AGE-SECRET-KEY-1S7CWPUE7ZTUT09GDHDXQ5J9E0E5HPF5TQ3EUJFKZMF0YN2JLY8HQJ7RZ97 diff --git a/simple-sops/.kluctl.yml b/simple-sops/.kluctl.yml new file mode 100644 index 0000000..386fee2 --- /dev/null +++ b/simple-sops/.kluctl.yml @@ -0,0 +1,6 @@ +targets: + - name: simple + args: + environment: simple + + diff --git a/simple-sops/.sops.yaml b/simple-sops/.sops.yaml new file mode 100644 index 0000000..37a4247 --- /dev/null +++ b/simple-sops/.sops.yaml @@ -0,0 +1,4 @@ +creation_rules: + - encrypted_regex: '^((?i)(secret($|[^N])|values|data|stringData|username|auth|.*(credentials|token|key|private|pass|secret|domain|ssid|webhook).*))$' + #path_regex: .*.(json|yml|yaml|sops|key) + age: 'age17putd49qeggegt8nlwvtruq8fut5lsny3894e0vta9mpn6udvpvs8809zy' # `,` separated list of keys public keys diff --git a/simple-sops/.templateignore b/simple-sops/.templateignore new file mode 100644 index 0000000..eecc942 --- /dev/null +++ b/simple-sops/.templateignore @@ -0,0 +1 @@ +*.example diff --git a/simple-sops/README.md b/simple-sops/README.md new file mode 100644 index 0000000..2665c2d --- /dev/null +++ b/simple-sops/README.md @@ -0,0 +1,85 @@ + +# SOPS integration example + +## init + +Prepare env: +``` +kwokctl --name simple create cluster +export KUBECONFIG=$HOME/.kwok/clusters/$ENV/kubeconfig.yaml + +export KLUCTL_RENDER_OUTPUT_DIR=./.build +export SOPS_AGE_KEY_FILE=$PWD/.env.age +``` + +For this example, age is used for sops encryption. +Generated private key is for example attached `.env.age` in this repo (insecure) and the public part was added to `.sops.yml`: +``` +age-keygen -o .env.age +``` + +## encrypting +sops -e --in-place secrets.yml + +## editing (already encrypted file) +sops --in-place secrets.yml + +## decrypt single file +sops -d secrets.yml +sops -d deployment/nginx/secret.yml +sops -d deployment/nginx/config/server.key +sops -d deployment/nginx/config/server-config.yml +``` + +## secrets + +The `deployment/nginx/[kustomization.yml](deploy/nginx/kustomiation.yml) contains all the secrets applied: + +``` +resources: + - secret.yml # deploy Secret kind, name: 'certificates' + +secretGenerator: + - name: credentials + literals: # interpolation example + - PASSWORD={{ secrets.nginx.credentials.password }} + + - name: server-config + files: + - ./config/server-config.yml # (NOT IMPLEMENTED, sops encrypted file) + - name: certificates-from-files + files: + - server.crt=./config/server.crt + - server.key=./config/server.key # (NOT IMPLEMENTED, SOPS encrypted file) + +``` + +## apply +``` +kluctl deploy -t simple --no-obfuscate --yes +``` + +``` +❯ kubectl get secret -n simple +NAME TYPE DATA AGE +certificates Opaque 2 53m +certificates-from-files Opaque 2 32m +credentials Opaque 1 53m +server-config Opaque 2 32m +``` + + +## review secrets +``` +kubectl get secret -n simple credentials -o json | jq '.data.PASSWORD' -r | base64 -d +kubectl get secret -n simple -o json certificates | jq '.data."server.key"' -r | base64 -d +``` + + +Mind, some variants of secretGenerator are not yet implemented or rather say are below `kluctl` level of visibility. These +secret if SOPS encrypted will not get decrypted during render: +``` +kubectl get secret -n simple -o json certificates-from-files | jq '.data."server.key"' -r | base64 -d +kubectl get secret -n simple -o json server-config | jq '.data."server-config.yml"' -r | base64 -d + +``` diff --git a/simple-sops/deployment.yml b/simple-sops/deployment.yml new file mode 100644 index 0000000..fe50b14 --- /dev/null +++ b/simple-sops/deployment.yml @@ -0,0 +1,9 @@ +deployments: + - include: deployment + +commonLabels: + examples.kluctl.io/environment: "{{ args.environment }}" + examples.kluctl.io/deployment-project: k8s-deployment-simple + +vars: + - file: secrets.yml diff --git a/simple-sops/deployment/deployment.yml b/simple-sops/deployment/deployment.yml new file mode 100644 index 0000000..ad53972 --- /dev/null +++ b/simple-sops/deployment/deployment.yml @@ -0,0 +1,4 @@ +deployments: + - path: nginx + +overrideNamespace: "{{ args.environment }}" diff --git a/simple-sops/deployment/nginx/config/server-config.yml b/simple-sops/deployment/nginx/config/server-config.yml new file mode 100644 index 0000000..c526d49 --- /dev/null +++ b/simple-sops/deployment/nginx/config/server-config.yml @@ -0,0 +1,23 @@ +data: + some: ENC[AES256_GCM,data:CJcYHFWN,iv:H5fvWGCHMSQzTlNBm6oeR3NU1X1gLeyzStBD5070AxM=,tag:PQ8ZPQmxwK558Px5VGbC7w==,type:str] + for: ENC[AES256_GCM,data:uuEJ4GQ/CJS/g0JQuSTK90A=,iv:7OXKS7D8xcPIrnZqx7jaIP5mE8r+E0yPhu+WGowDLiE=,tag:fEdAkjlwkNW7wT6SzK4BvQ==,type:str] +sops: + kms: [] + gcp_kms: [] + azure_kv: [] + hc_vault: [] + age: + - recipient: age17putd49qeggegt8nlwvtruq8fut5lsny3894e0vta9mpn6udvpvs8809zy + enc: | + -----BEGIN AGE ENCRYPTED FILE----- + YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSB2QVZpamowYWZzQmIycWNp + WVljbU5tUXpUTlZhcDhKc25hWERrZGNSZUM4CjRsYjZnQ2hGWWpodnVNbVZlM0Q3 + d2xsM3dpdXNYV2hYZEdaRDU5R0QydUkKLS0tIGJ4NlcwWVpPdVZ1bDRLN2RBVXVC + S3Z5TURPby93MXFsRFZES1YrOUZWQlEKPsO05M3d/q+KPgwu1AkoLiRNZE3WzpUy + UDw1mI4iuRpZw67c/drRuLlE0itw9Dqy+71pyWqe08CGKIw3zBe48A== + -----END AGE ENCRYPTED FILE----- + lastmodified: "2023-04-24T17:14:45Z" + mac: ENC[AES256_GCM,data:Y8cc8nDuYDP1VYFy6iyD7Wg/8Jc7ZxMrkbEp7CeoaXMnZitpwd1vwfsp3YHXouhs6G5Il+LNjsNjfvh0teEUYQQv7gty6FOcTJUa5nmxwNEHXCjexJewIPX6Nrtd5A5U3ro94yPOs/qT3XMAitHrdzRlmtdxojQJIdJdKQ859WY=,iv:HJFh0OYHvuXXBEcc2Z7f1crPCuVJX2liVEh7ZMURYLs=,tag:qcwjX0iND6MviZHK85+A5g==,type:str] + pgp: [] + encrypted_regex: ^((?i)(secret($|[^N])|values|data|stringData|username|auth|.*(credentials|token|key|private|pass|secret|domain|ssid|webhook).*))$ + version: 3.7.3 diff --git a/simple-sops/deployment/nginx/config/server-config.yml.example b/simple-sops/deployment/nginx/config/server-config.yml.example new file mode 100644 index 0000000..c6705fb --- /dev/null +++ b/simple-sops/deployment/nginx/config/server-config.yml.example @@ -0,0 +1,4 @@ +whatever: + data: + some: config + for: nginx or it's app diff --git a/simple-sops/deployment/nginx/config/server.crt b/simple-sops/deployment/nginx/config/server.crt new file mode 100644 index 0000000..c8d4dd4 --- /dev/null +++ b/simple-sops/deployment/nginx/config/server.crt @@ -0,0 +1 @@ +MISSING diff --git a/simple-sops/deployment/nginx/config/server.key b/simple-sops/deployment/nginx/config/server.key new file mode 100644 index 0000000..034b37b --- /dev/null +++ b/simple-sops/deployment/nginx/config/server.key @@ -0,0 +1,20 @@ +{ + "data": "ENC[AES256_GCM,data:6R5edYbBE5x/cqV5VgDr+PYZXHZqpQqMMlMFlaJ4xvtB8UaqrlXy747hpN0EJEi2r0yZN9EBGUvJdHGStcY0YRhEGgmDudjH4BroUE9qFVyYEV1yhSBCOTVvSwqeQQ==,iv:UT3b7lRNbNf6tFxN8HT4DJYnPagEu9h+M1OxrG9ZQBQ=,tag:GdhL3Q3cONJmlUi4TOxCTg==,type:str]", + "sops": { + "kms": null, + "gcp_kms": null, + "azure_kv": null, + "hc_vault": null, + "age": [ + { + "recipient": "age17putd49qeggegt8nlwvtruq8fut5lsny3894e0vta9mpn6udvpvs8809zy", + "enc": "-----BEGIN AGE ENCRYPTED FILE-----\nYWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSA5VnZaNUZqL1UxdU9CQ0dp\nYm8wMlNZeVFCK3NnbzlQdHd3QjRIRS9lQUFzCnVvYVRMTkpRMEhjQkcyeUpvN2Jy\nWDBzVjYrN3k1UXgyOERUWWFDdTdyQVkKLS0tIDJtZU5DM1VmUythTk9hNFR0VGRT\nZ0pjUXY2WDBBRDdOdXZJMzJhazlQOUUKolQz1P8NyNw2zX6SiEC5XubLqDEGPkPY\nEi2ooT24LF8ePJ6jNUtSEUBszJjpY/4KufMCyqmcCCq+Se4uA/j+oA==\n-----END AGE ENCRYPTED FILE-----\n" + } + ], + "lastmodified": "2023-04-24T16:40:39Z", + "mac": "ENC[AES256_GCM,data:wz1TjJOY1+nkioxrIAEogCv2UhELg75M76A6zcsy5c87zWftjHGjfGMhrD9xqHpXHiDKwuLHmdT0fDkLvJhzf6/zAlbMFKBowlwB5ZSG/F8jRHmxounSAjlnrCbpFaf3NuP5Bn8zJ68ZiaZzraImXvGlIeasrynMXIRQ6VqPU1U=,iv:c/2D0qxBcfxIJz833EbJZfH+OK63fEr3n6wHCEqdrHw=,tag:/H0+1wYOXbFLUq8mYSoQnA==,type:str]", + "pgp": null, + "encrypted_regex": "^((?i)(secret($|[^N])|values|data|stringData|username|auth|.*(token|key|private|pass|secret|domain|ssid|webhook).*))$", + "version": "3.7.3" + } +} \ No newline at end of file diff --git a/simple-sops/deployment/nginx/config/server.key.example b/simple-sops/deployment/nginx/config/server.key.example new file mode 100644 index 0000000..22bd519 --- /dev/null +++ b/simple-sops/deployment/nginx/config/server.key.example @@ -0,0 +1,4 @@ +-----BEGIN PRIVATE KEY----- +base64 encoded data +base64 encoded data +-----END PRIVATE KEY----- diff --git a/simple-sops/deployment/nginx/deploy.yml b/simple-sops/deployment/nginx/deploy.yml new file mode 100644 index 0000000..ae2d751 --- /dev/null +++ b/simple-sops/deployment/nginx/deploy.yml @@ -0,0 +1,21 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: nginx-deployment + labels: + app: nginx +spec: + replicas: 1 + selector: + matchLabels: + app: nginx + template: + metadata: + labels: + app: nginx + spec: + containers: + - name: nginx + image: nginx:1.14.2 + ports: + - containerPort: 80 diff --git a/simple-sops/deployment/nginx/kustomization.yml b/simple-sops/deployment/nginx/kustomization.yml new file mode 100644 index 0000000..5a4fb04 --- /dev/null +++ b/simple-sops/deployment/nginx/kustomization.yml @@ -0,0 +1,24 @@ +apiVersion: kustomize.config.k8s.io/v1beta1 +kind: Kustomization + +resources: +- namespace.yml +- secret.yml # deploy Secret kind, name: 'certificates' +- deploy.yml + +secretGenerator: +- name: credentials + literals: + - PASSWORD={{ secrets.nginx.credentials.password }} + +- name: server-config + files: + - ./config/server-config.yml +- name: certificates-from-files + files: + - server.crt=./config/server.crt + - server.key=./config/server.key + + +generatorOptions: + disableNameSuffixHash: true diff --git a/simple-sops/deployment/nginx/namespace.yml b/simple-sops/deployment/nginx/namespace.yml new file mode 100644 index 0000000..1b561a9 --- /dev/null +++ b/simple-sops/deployment/nginx/namespace.yml @@ -0,0 +1,4 @@ +apiVersion: v1 +kind: Namespace +metadata: + name: "{{ args.environment }}" diff --git a/simple-sops/deployment/nginx/secret.yml b/simple-sops/deployment/nginx/secret.yml new file mode 100644 index 0000000..e72ed1a --- /dev/null +++ b/simple-sops/deployment/nginx/secret.yml @@ -0,0 +1,28 @@ +apiVersion: v1 +kind: Secret +metadata: + name: certificates + namespace: simple +stringData: + server.crt: ENC[AES256_GCM,data:CE24oLz9PQ==,iv:hvUdYRAdGPb1wBeb+j3TGIf8F8Cw8pbD+D2aWIwTIF4=,tag:0HZLK+45Gx5/ldvh6mx8cQ==,type:str] + server.key: ENC[AES256_GCM,data:XMCltAPR939f1WgKCeAECaxPngW5NHEMTo33/OASaoGuc5otWwhgzoIAXCNtIg01MSe2pWdctfhcFdthpPYlPDrj2fvTB/1ko5kkyG0iaYlFt1QfQeD+M66LdCtq7w==,iv:SBGWvQ2npCEjzirs0IC/jeSYzFrUTqCcxisBuAWGH7k=,tag:fmr+xjERO60M7JHNX7+8yw==,type:str] +sops: + kms: [] + gcp_kms: [] + azure_kv: [] + hc_vault: [] + age: + - recipient: age17putd49qeggegt8nlwvtruq8fut5lsny3894e0vta9mpn6udvpvs8809zy + enc: | + -----BEGIN AGE ENCRYPTED FILE----- + YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSB4d3JJeXozRVN2R3lYTG1K + QWt0N3JENlpTcUt1R2xSd1FPRisyTk11VEZvClNORWNQczhvOVo2dnZ1TU1ib1FN + MFZQeUM4aG5wQmVnamQ0cmR6T05EQm8KLS0tIDNyYkhVemNwUHpNcitrZXJzU1Zx + MXFxYmF3VHhWVGx4V0hDRVJweGFlcFkKJ+2G0YtjXBKS8vFLimY7Yq20SqxLLIGn + AzByE3hw+AdYjJrX4wObRwQTbjNy1OBwoV4n9QDVUY6prnMwRfYEKg== + -----END AGE ENCRYPTED FILE----- + lastmodified: "2023-04-24T16:38:58Z" + mac: ENC[AES256_GCM,data:Tk58iNAUTNCJwPt/9UfZAhFMrZn3klD7bB1uvM5IoM2AuQSr45znp7qLmaZDWgqf5DwPERrNX9zbGrgbazQfGAwkVHhF1j7ZRjM0wtQXOECY1asb4NSvCDfqsKpV/xoWCYVPcagSSq5OfTsLsLJuwWXsAakYN1jX7WVGfXp3pMQ=,iv:9aY8Isg+K73cNzgoXD1BVrTHJOSSjE9FuDuvxQNdAj4=,tag:kMs6UiTzw/gpxC2FwRa/fg==,type:str] + pgp: [] + encrypted_regex: ^((?i)(secret($|[^N])|values|data|stringData|username|auth|.*(token|key|private|pass|secret|domain|ssid|webhook).*))$ + version: 3.7.3 diff --git a/simple-sops/deployment/nginx/secret.yml.example b/simple-sops/deployment/nginx/secret.yml.example new file mode 100644 index 0000000..98c0715 --- /dev/null +++ b/simple-sops/deployment/nginx/secret.yml.example @@ -0,0 +1,12 @@ +apiVersion: v1 +kind: Secret +metadata: + name: certificates + namespace: simple +stringData: + server.crt: MISSING + server.key: | + -----BEGIN PRIVATE KEY----- + base64 encoded data + base64 encoded data + -----END PRIVATE KEY----- diff --git a/simple-sops/secrets.yml b/simple-sops/secrets.yml new file mode 100644 index 0000000..f3cbf4f --- /dev/null +++ b/simple-sops/secrets.yml @@ -0,0 +1,24 @@ +secrets: + nginx: + credentials: + password: ENC[AES256_GCM,data:fvvyUhkR,iv:e3J+VHVwDhgx/vST1cJMomZ1wVlupTZGAlQFUkF2Xso=,tag:CCZnC2WBXq08p4VMl4CEDA==,type:str] +sops: + kms: [] + gcp_kms: [] + azure_kv: [] + hc_vault: [] + age: + - recipient: age17putd49qeggegt8nlwvtruq8fut5lsny3894e0vta9mpn6udvpvs8809zy + enc: | + -----BEGIN AGE ENCRYPTED FILE----- + YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSByU2ozcFM1ZXhqcHR0bmNv + YktMUFF0U25xMW1VekszK1JJSk0wbTNHaHh3ClhXdmk0UzVhRFAwYzB3NU1UaTF1 + SVUvNmJycVJIYjl1NWd2S2p5STBpNlkKLS0tIGc3algwNzNaOUFqUFVXVitCNXpJ + UzRweFU2ZHVNT3Y2WEZ4YStFMnJDV3MKIPZW1tlD9WgcsZLmNQD7RJCZadvnf3il + JJM4g9J2ALWdi6y/syB0weO5TMMBD758PZ5byTBKh0iIIWkrcX1dgA== + -----END AGE ENCRYPTED FILE----- + lastmodified: "2023-04-24T16:01:53Z" + mac: ENC[AES256_GCM,data:mo/JaAD4nimVqLQ/P/jdjbTuFoc4DN6R6dCoheF9tM0aqBbtanlCbMLVC+XsZxiA7Y7vC3N2SeLvmnfPkK/uFPLcYUgIjxX+cMf9bVBaGy5xfafPlvzp/Me4VWU2TxbY35gG6028Hjv/Cv+Y89MP5I3TS+0f0ebce15yxD+rWY0=,iv:Iwqp+FEBHz2aMmvYRNZ7Rk6j98SlUVq6HibR/g+OTfk=,tag:IBoGOHC7Pdwo/N+Gtj/Tcw==,type:str] + pgp: [] + encrypted_regex: ^((?i)(secret($|[^N])|values|data|stringData|username|auth|.*(token|key|private|pass|secret|domain|ssid|webhook).*))$ + version: 3.7.3 diff --git a/simple-sops/secrets.yml.example b/simple-sops/secrets.yml.example new file mode 100644 index 0000000..3d99dfb --- /dev/null +++ b/simple-sops/secrets.yml.example @@ -0,0 +1,5 @@ + +secrets: + nginx: + credentials: + password: rooted