Secrets Provider for Kubernetes
It is possible to consume Strongbox secrets in a Kubernetes environment through the use of a secrets provider. The secrets provider is a container that access secrets in Strongbox and populates files and/or the Kubernetes Secrets store.
This way an existing Kubernetes application does not have to use the Strongbox APIs directly, and can still be given access to secrets stored in Strongbox.
The kubernetes-secrets-provider repository
(https://gitlab.com/avassa-public/kubernetes-secrets-provider.git)
builds a container called avassa-mount-secrets
. The container can be
run in two different modes, as an initContainer
and as a regular
container
.
The secrets provider can provide Strongbox secrets both as one or more files and as Kubernetes secrets.
How secrets are mapped and accessed is controlled through Kubernetes
pod annotations. The annotations tells the secrets provider how to
access an Avassa system and also which secrets should be mapped and
how they should be mapped. Access to the annotations are provided
thought the Downward API by mounting the metadata.annotations
as a
volume in the container.
A pod specification can, for example, look like this:
apiVersion: v1
kind: Pod
metadata:
name: auth-demo
annotations:
avassa.io/api-host: api.theater-operation.avassa.io
avassa.io/tenant: theater-operation
avassa.io/service: theater-ops
avassa.io/role: theater-ops-role
avassa.io/ca-cert: |-
-----BEGIN CERTIFICATE-----
MIICGzCCAcCgAwIBAgITAIGw58I85P6bWhwIX2Qo8hcHHTAKBggqhkjOPQQDAjBj
MRgwFgYDVQQDEw9BdmFzc2EgQVBJIHJvb3QxEjAQBgNVBAcTCVN0b2NraG9sbTEL
MAkGA1UEBhMCU0UxDzANBgNVBAoTBkF2YXNzYTEVMBMGA1UECxMMZGlzdHJpYnV0
aW9uMCIYDzIwMjIwNDIxMDcxMTMwWhgPMjAyNTA4MzAxMDQ3MzBaMGMxGDAWBgNV
BAMTD0F2YXNzYSBBUEkgcm9vdDESMBAGA1UEBxMJU3RvY2tob2xtMQswCQYDVQQG
EwJTRTEPMA0GA1UEChMGQXZhc3NhMRUwEwYDVQQLEwxkaXN0cmlidXRpb24wWTAT
BgcqhkjOPQIBBggqhkjOPQMBBwNCAAQFdfEMHr6X8fuudI7fI01UtEzbTW0DHLhg
v9G80P39l8D9FKY8IaRmILkn+wKgO/jCOGDBTXQHICnALCEZqWNUo08wTTAOBgNV
HQ8BAf8EBAMCAYYwEgYDVR0TAQH/BAgwBgEB/wIBATAnBgNVHR8EIDAeMBygGqAY
hhZodHRwOi8vY3JsLmF2YXNzYS5uZXQvMAoGCCqGSM49BAMCA0kAMEYCIQCf/oBh
6PSuZ23ODIgtdmOY4tC2UmSP10OY+bikzCqjFAIhAJb6gc/Mb5hKbgtwRJ2BdIPk
s/ujLEF3Tgc70oUona1Y
-----END CERTIFICATE-----
# create a file for each entry in the secrets map
avassa.io/vault.credentials.admin: files
# store the secrets map in the file credentials.json
avassa.io/vault.credentials.oper: json/credentials.json
# store a single entry in the secrets map in the file user.txt
avassa.io/vault.credentials.oper.user: user.txt
spec:
serviceAccountName: nginx-sa
volumes:
- name: shared-data
emptyDir: {}
- name: podinfo
downwardAPI:
items:
- path: annotations
fieldRef:
fieldPath: metadata.annotations
- name: avassa-secrets
emptyDir:
medium: Memory
containers:
- name: nginx
image: nginx
volumeMounts:
- name: shared-data
mountPath: /usr/share/nginx/html
- name: avassa-secrets
mountPath: /avassa/secrets
initContainers:
- name: init-avassa-secrets
image: avassa-mount-secrets:0.1
imagePullPolicy: Never
volumeMounts:
- name: podinfo
mountPath: /avassa/podinfo
- name: avassa-secrets
mountPath: /avassa/secrets
hostNetwork: false
dnsPolicy: Default
Before this pod can be loaded some preparation is needed.
Preparing the Avassa System
Before the avassa-mount-secrets
container can be used the
Avassa system must be setup to allow the Kubernetes cluster
to authenticate using Kubernetes Service Account Tokens.
Before Avassa can be configured some setup in Kubernetes is required.
Configure Kubernetes
First, create a service account for the application by applying the following using kubectl.
apiVersion: v1
kind: ServiceAccount
metadata:
name: theater-operations
namespace: default
Assign the system:auth-delegator
role to the service account token
to allow the remote Strongbox authenticator to use the applications
service account token to invoke the token review endpoint to validate
the service account token.
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: role-tokenreview-binding
namespace: default
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: system:auth-delegator
subjects:
- kind: ServiceAccount
name: theater-operations
namespace: default
In order for the avassa-mount-secrets
container to update
secrets in the Kubernetes Secrets store, it must be given
permission to perform operations towards the store.
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: my-secrets-clusterrole
rules:
- apiGroups: [""]
resources: ["secrets"]
verbs: ["get", "list", "watch", "create", "update", "patch", "delete"]
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: read-secrets-global
namespace: default
roleRef: # referring to your ClusterRole
kind: ClusterRole
name: my-secrets-clusterrole
apiGroup: rbac.authorization.k8s.io
subjects:
- kind: ServiceAccount
name: theater-operations
namespace: default
Assign a service account to a pod using the serviceAccountName
setting, eg:
apiVersion: v1
kind: Pod
metadata:
name: curtain-control
spec:
serviceAccountName: theater-operations
containers:
- name: alpine
image: alpine
command:
- /bin/sh
- "-c"
- "sleep 60m"
Configure Strongbox for Kubernetes authentication
Strongbox also needs to be configured to accept service
account tokens as valid credentials. First extract the
API certificate from Kubernetes (used for the api-ca-cert
parameter below).
kubectl config view --raw --minify --flatten --output \
'jsonpath={.clusters[].cluster.certificate-authority-data}' | \
base64 --decode
-----BEGIN CERTIFICATE-----
MIIDBjCCAe6gAwIBAgIBATANBgkqhkiG9w0BAQsFADAVMRMwEQYDVQQDEwptaW5p
a3ViZUNBMB4XDTIxMDkyNjA4NTE1NloXDTMxMDkyNTA4NTE1NlowFTETMBEGA1UE
AxMKbWluaWt1YmVDQTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALPj
RABeQOTAY9Vj4IORJ1oeAdHCXRvu6sLWokuX0rZuKj80YIJSiqXOsh2Djp8aD1fG
EU89+fJNVV/3Ba5pe9NODbp597xAs/wpzmlurM/O99czoOxNsfd6pu0KpsRZgzBv
UXzc9offqfr+bbFBrb6VD0fZ8q5ZJ+BupQcdc46/pm31AEG3MfmGv0jVU4d/RZTm
+s4vrjrCEb255XTdWFHMi/bKMRNKRCoTHVAi01FbdHEivzVlFzObgp+UbldZf1v9
GvqXzSmXLX87nn4Fa3JroPhNCajYiJikEBV5hIAe6RpGg42zr8GDrDj0e5CvpTOu
F8leq8hjEvknEk3XQBECAwEAAaNhMF8wDgYDVR0PAQH/BAQDAgKkMB0GA1UdJQQW
MBQGCCsGAQUFBwMCBggrBgEFBQcDATAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQW
BBTBXYN94F5bU0shR57gmFiNtyRahDANBgkqhkiG9w0BAQsFAAOCAQEAl9mr8t+M
FCAsn2ZIuILwZeiOhNXqyftFR2la47jJmYFtV6FZwMG7zNWOZlXYKrfw8mrRsaAB
a2OvItNipywU54mJaN4OV9PuOadz3KjB3sZ78yXsteXgH3+TxNOwe4LW1mxeyxdL
2JBCPmgrAt0VqekN1q0RRFyI/5JkU6Q+y1rpFV+cLvJGnX47Icgbgf/BGM4Bo30q
1U0iTWrfcVUNQwpYtbHYPnbDD3F8E4FuX+G8J2QNgjHXGKHdCkM/s9IBKr/SLgiM
kv/++NI+D3yABup4kHRnAWPLxAsBVB/v4p8o6yLB3jwIDxHwC3LU4tyQ2n3a/RFR
ceaTK5VvI8G+xg==
-----END CERTIFICATE-----
Then extract a Service Account token that can be used to
access the Token Review service in Kubernetes (used
in the token-review-jwt
parameter below).
kubectl describe secret theater-operations
Name: theater-operations-token-ljckk
Namespace: default
Labels: <none>
Annotations: kubernetes.io/service-account.name: theater-operations
kubernetes.io/service-account.uid: 66b26fef-6e9a-47ba-bea1-8ec1936b9551
Type: kubernetes.io/service-account-token
Data
====
ca.crt: 1111 bytes
namespace: 7 bytes
token: eyJhbGciOiJSUzI1NiIsImtpZCI6ImVGRXpUeGJORzI3Q3A0R1RDT1d1dWhINHU2c09CSDlqdjZINWZ6dXdYejAifQ.eyJpc3MiOiJrdWJlcm5ldGVzL3NlcnZpY2VhY2NvdW50Iiwia3ViZXJuZXRlcy5pby9zZXJ2aWNlYWNjb3VudC9uYW1lc3BhY2UiOiJkZWZhdWx0Iiwia3ViZXJuZXRlcy5pby9zZXJ2aWNlYWNjb3VudC9zZWNyZXQubmFtZSI6InRoZWF0ZXItb3BlcmF0aW9ucy10b2tlbi1samNrayIsImt1YmVybmV0ZXMuaW8vc2VydmljZWFjY291bnQvc2VydmljZS1hY2NvdW50Lm5hbWUiOiJ0aGVhdGVyLW9wZXJhdGlvbnMiLCJrdWJlcm5ldGVzLmlvL3NlcnZpY2VhY2NvdW50L3NlcnZpY2UtYWNjb3VudC51aWQiOiI2NmIyNmZlZi02ZTlhLTQ3YmEtYmVhMS04ZWMxOTM2Yjk1NTEiLCJzdWIiOiJzeXN0ZW06c2VydmljZWFjY291bnQ6ZGVmYXVsdDp0aGVhdGVyLW9wZXJhdGlvbnMifQ.DKzkbgRseQWIkSv6q7QHOlS3z9f8Y0NFNWFQsfMnyLBIIq2xsvSfRCAqh2Ps4vUr5xzCqlA16p0llFQs-MVwTvN6StXaAw6MfgAXQcqSOWYmPi5nKRTIyXQtsz5rEBZaz6hKVilek6KhIYCNeCAgpLilVcz7i55qtdHsz1JNUgWd7HqUDPwBLfx4BILY3B3L7myX3EE7WgpxLqqAKQ40mL9TVD2CpOa6Zw1X1ovP5ANTgUVjrDAosDmlL-BKNMsJOmb4LRzMr5OlY6oFRbuSOsZZ_NtI7WOE5zA8yoy18jSOqg33FYwMfFixjvjZRm1XQMV5DYD7JZH_GmrAJksUVw
Then configure Strongbox to accept service account tokens as valid credentials.
In Kubernetes default tokens use 'kubernetes/serviceaccount' as issuer, however ephemeral tokens use the api-servers service-account-issuer setting, which is often a URL. Both may have to be configured as valid issuers.
supctl create strongbox authentication kubernetes <<EOF
name: theater-ops
host: 192.168.0.147
jwks-uri: "https://192.168.0.147/openid/v1/jwks"
server-name-indication: kubernetes
api-ca-cert: |-
-----BEGIN CERTIFICATE-----
MIIDBjCCAe6gAwIBAgIBATANBgkqhkiG9w0BAQsFADAVMRMwEQYDVQQDEwptaW5p
a3ViZUNBMB4XDTIxMDkyNjA4NTE1NloXDTMxMDkyNTA4NTE1NlowFTETMBEGA1UE
AxMKbWluaWt1YmVDQTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALPj
RABeQOTAY9Vj4IORJ1oeAdHCXRvu6sLWokuX0rZuKj80YIJSiqXOsh2Djp8aD1fG
EU89+fJNVV/3Ba5pe9NODbp597xAs/wpzmlurM/O99czoOxNsfd6pu0KpsRZgzBv
UXzc9offqfr+bbFBrb6VD0fZ8q5ZJ+BupQcdc46/pm31AEG3MfmGv0jVU4d/RZTm
+s4vrjrCEb255XTdWFHMi/bKMRNKRCoTHVAi01FbdHEivzVlFzObgp+UbldZf1v9
GvqXzSmXLX87nn4Fa3JroPhNCajYiJikEBV5hIAe6RpGg42zr8GDrDj0e5CvpTOu
F8leq8hjEvknEk3XQBECAwEAAaNhMF8wDgYDVR0PAQH/BAQDAgKkMB0GA1UdJQQW
MBQGCCsGAQUFBwMCBggrBgEFBQcDATAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQW
BBTBXYN94F5bU0shR57gmFiNtyRahDANBgkqhkiG9w0BAQsFAAOCAQEAl9mr8t+M
FCAsn2ZIuILwZeiOhNXqyftFR2la47jJmYFtV6FZwMG7zNWOZlXYKrfw8mrRsaAB
a2OvItNipywU54mJaN4OV9PuOadz3KjB3sZ78yXsteXgH3+TxNOwe4LW1mxeyxdL
2JBCPmgrAt0VqekN1q0RRFyI/5JkU6Q+y1rpFV+cLvJGnX47Icgbgf/BGM4Bo30q
1U0iTWrfcVUNQwpYtbHYPnbDD3F8E4FuX+G8J2QNgjHXGKHdCkM/s9IBKr/SLgiM
kv/++NI+D3yABup4kHRnAWPLxAsBVB/v4p8o6yLB3jwIDxHwC3LU4tyQ2n3a/RFR
ceaTK5VvI8G+xg==
-----END CERTIFICATE-----
token-review-jwt: eyJhbGciOiJSUzI1NiIsImtpZCI6ImVGRXpUeGJORzI3Q3A0R1RDT1d1dWhINHU2c09CSDlqdjZINWZ6dXdYejAifQ.eyJpc3MiOiJrdWJlcm5ldGVzL3NlcnZpY2VhY2NvdW50Iiwia3ViZXJuZXRlcy5pby9zZXJ2aWNlYWNjb3VudC9uYW1lc3BhY2UiOiJkZWZhdWx0Iiwia3ViZXJuZXRlcy5pby9zZXJ2aWNlYWNjb3VudC9zZWNyZXQubmFtZSI6InRoZWF0ZXItb3BlcmF0aW9ucy10b2tlbi1samNrayIsImt1YmVybmV0ZXMuaW8vc2VydmljZWFjY291bnQvc2VydmljZS1hY2NvdW50Lm5hbWUiOiJ0aGVhdGVyLW9wZXJhdGlvbnMiLCJrdWJlcm5ldGVzLmlvL3NlcnZpY2VhY2NvdW50L3NlcnZpY2UtYWNjb3VudC51aWQiOiI2NmIyNmZlZi02ZTlhLTQ3YmEtYmVhMS04ZWMxOTM2Yjk1NTEiLCJzdWIiOiJzeXN0ZW06c2VydmljZWFjY291bnQ6ZGVmYXVsdDp0aGVhdGVyLW9wZXJhdGlvbnMifQ.DKzkbgRseQWIkSv6q7QHOlS3z9f8Y0NFNWFQsfMnyLBIIq2xsvSfRCAqh2Ps4vUr5xzCqlA16p0llFQs-MVwTvN6StXaAw6MfgAXQcqSOWYmPi5nKRTIyXQtsz5rEBZaz6hKVilek6KhIYCNeCAgpLilVcz7i55qtdHsz1JNUgWd7HqUDPwBLfx4BILY3B3L7myX3EE7WgpxLqqAKQ40mL9TVD2CpOa6Zw1X1ovP5ANTgUVjrDAosDmlL-BKNMsJOmb4LRzMr5OlY6oFRbuSOsZZ_NtI7WOE5zA8yoy18jSOqg33FYwMfFixjvjZRm1XQMV5DYD7JZH_GmrAJksUVw
valid-issuers:
- https://kubernetes.default.svc.cluster.local
- kubernetes/serviceaccount
EOF
A Kubernetes login role must also be configured, eg
supctl create strongbox authentication kubernetes theater-ops roles <<EOF
name: theater-ops-role
token-policies:
- theater-ops-policy
verbose-logging: true
bound-service-account-names:
- "*"
bound-service-account-namespaces:
- default
EOF
And the theater-ops-policy
must be configured to give the
pod access to the secret.
supctl create policy policies <<EOF
name: theater-ops-policy
rest-api:
rules:
- path: /v1/*/strongbox/vaults/credentials/secrets/admin
operations:
read: allow
- path: /v1/*/strongbox/vaults/credentials/secrets/oper
operations:
read: allow
EOF
"""
The API CA certificate needs to be extracted.
supctl do get-api-ca-cert
cert: |-
-----BEGIN CERTIFICATE-----
MIICGzCCAcCgAwIBAgITAIGw58I85P6bWhwIX2Qo8hcHHTAKBggqhkjOPQQDAjBj
MRgwFgYDVQQDEw9BdmFzc2EgQVBJIHJvb3QxEjAQBgNVBAcTCVN0b2NraG9sbTEL
MAkGA1UEBhMCU0UxDzANBgNVBAoTBkF2YXNzYTEVMBMGA1UECxMMZGlzdHJpYnV0
aW9uMCIYDzIwMjIwNDIxMDcxMTMwWhgPMjAyNTA4MzAxMDQ3MzBaMGMxGDAWBgNV
BAMTD0F2YXNzYSBBUEkgcm9vdDESMBAGA1UEBxMJU3RvY2tob2xtMQswCQYDVQQG
EwJTRTEPMA0GA1UEChMGQXZhc3NhMRUwEwYDVQQLEwxkaXN0cmlidXRpb24wWTAT
BgcqhkjOPQIBBggqhkjOPQMBBwNCAAQFdfEMHr6X8fuudI7fI01UtEzbTW0DHLhg
v9G80P39l8D9FKY8IaRmILkn+wKgO/jCOGDBTXQHICnALCEZqWNUo08wTTAOBgNV
HQ8BAf8EBAMCAYYwEgYDVR0TAQH/BAgwBgEB/wIBATAnBgNVHR8EIDAeMBygGqAY
hhZodHRwOi8vY3JsLmF2YXNzYS5uZXQvMAoGCCqGSM49BAMCA0kAMEYCIQCf/oBh
6PSuZ23ODIgtdmOY4tC2UmSP10OY+bikzCqjFAIhAJb6gc/Mb5hKbgtwRJ2BdIPk
s/ujLEF3Tgc70oUona1Y
-----END CERTIFICATE-----
Accessing Secrets
Once both Kubernetes and Avassa has been set up for authentication the
avassa-mount-secrets
container can be used to access secrets stored
in Strongbox.
Directives to the container is provided as annotations in the pod, ie
apiVersion: v1
kind: Pod
metadata:
name: auth-demo
annotations:
avassa.io/api-host: api.theater-operation.avassa.io
avassa.io/tenant: theater-operation
avassa.io/service: theater-ops
avassa.io/role: theater-ops-role
avassa.io/ca-cert: |-
-----BEGIN CERTIFICATE-----
MIICGzCCAcCgAwIBAgITAIGw58I85P6bWhwIX2Qo8hcHHTAKBggqhkjOPQQDAjBj
MRgwFgYDVQQDEw9BdmFzc2EgQVBJIHJvb3QxEjAQBgNVBAcTCVN0b2NraG9sbTEL
MAkGA1UEBhMCU0UxDzANBgNVBAoTBkF2YXNzYTEVMBMGA1UECxMMZGlzdHJpYnV0
aW9uMCIYDzIwMjIwNDIxMDcxMTMwWhgPMjAyNTA4MzAxMDQ3MzBaMGMxGDAWBgNV
BAMTD0F2YXNzYSBBUEkgcm9vdDESMBAGA1UEBxMJU3RvY2tob2xtMQswCQYDVQQG
EwJTRTEPMA0GA1UEChMGQXZhc3NhMRUwEwYDVQQLEwxkaXN0cmlidXRpb24wWTAT
BgcqhkjOPQIBBggqhkjOPQMBBwNCAAQFdfEMHr6X8fuudI7fI01UtEzbTW0DHLhg
v9G80P39l8D9FKY8IaRmILkn+wKgO/jCOGDBTXQHICnALCEZqWNUo08wTTAOBgNV
HQ8BAf8EBAMCAYYwEgYDVR0TAQH/BAgwBgEB/wIBATAnBgNVHR8EIDAeMBygGqAY
hhZodHRwOi8vY3JsLmF2YXNzYS5uZXQvMAoGCCqGSM49BAMCA0kAMEYCIQCf/oBh
6PSuZ23ODIgtdmOY4tC2UmSP10OY+bikzCqjFAIhAJb6gc/Mb5hKbgtwRJ2BdIPk
s/ujLEF3Tgc70oUona1Y
-----END CERTIFICATE-----
The annotations are made available to the secrets provider container through the Kubernetes downward API as a mounted file system. Some annotations can also be provided through environment variables to allow two instances of the secrets provider to be run at the same time (both as an init container and an application container).
Init Container
When using the avassa-mount-secrets
container as an init
container it can pre-populate files and secrets in the
Kubernetes Secrets store to prepare an environment for a
regular container to run. The avassa-mount-secrets
container
will populate the secrets from Avassa Strongbox and then
exit, allowing an application container to start.
Application Container
It is also possible to run the avassa-mount-secrets
container
as an init container where it can periodically update secrets
from the Avassa System. By default it will check for changes
every 5 minutes.
If an application requires the secrets to be present before it is
started, and also requires secrets to be updated over time, then two
instances of the avassa-mount-secrets
container can be used, one as
an init container, and one as an application container. The mode that
the container should run as can then be set using environment
variables AVASSA_MODE
and AVASSA_UPDATE_INTERVAL
.
Mounting a Secret as a File
Secrets can be mounted as a set of files. Each secret
is mounted as a file where the key is used as filename,
and the value is stored as contents of the file.
The avassa-mount-secrets
container is instructed to
mount a secret in this way through the use of an annotation
on the format
avassa.io/vault.<vault-name>.<secret-name>: files
Suppose the following secret is stored in Strongbox in the
vault credentials
name: admin
data:
password: verysecret
user: admin@avassa.io
then the following annotation will result in two files
being created: user
and password
.
avassa.io/vault.credentials.admin: files
It is also possible to mount the value of a key in a secret in a named file using an annotation on the format:
avassa.io/vault.<vault-name>.<secret-name>.<key-id>: <file-name>
For example
avassa.io/vault.credentials.admin.user: user.txt
Finally, an entire secret can be mounted as a single file with
the secret dict
rendered in json format. This is achieved
with an annotation on the format:
avassa.io/vault.<vault-name>.<secret-name>: json/<file-name>
For example:
avassa.io/vault.credentials.admin: json/credentials.json
Populating Kubernetes Secret Store
An Avassa Strongbox secret can be mapped into the Kubernetes
Secrets store. This is achieved by storing a strongbox-map
value in the Kubernetes store. The map indicates that a key
should be created in the store taking the value from a key
in some Strongbox vault secret. The format is
<secret-key>: <vault-name>/<secret-name>/<key-id>
For example:
apiVersion: v1
kind: Secret
metadata:
name: db-credentials
type: Opaque
stringData:
strongbox-map: |-
username: credentials/admin/user
password: credentials/admin/password
An annotation is also needed to instruct the avassa-mount-secrets
container to populate the map in some given Kubernetes secret on
the form
avassa.io/k8s-secrets: <name of kubernetes secret>
For example
avassa.io/k8s-secrets: db-credentials
Example
Putting it all together in a pod description
Mount as files
Mount secrets as files in a Kubernetes Init container.
apiVersion: v1
kind: Pod
metadata:
name: auth-demo
annotations:
avassa.io/api-host: api.theater-operation.avassa.io
avassa.io/tenant: theater-operation
avassa.io/service: theater-ops
avassa.io/role: theater-ops-role
# create a file for each entry in the secrets map
avassa.io/vault.credentials.admin: files
# store the secrets map in the file credentials.json
avassa.io/vault.credentials.oper: json/credentials.json
# store a single entry in the secrets map in the file user.txt
avassa.io/vault.credentials.oper.user: user.txt
spec:
serviceAccountName: nginx-sa
volumes:
- name: shared-data
emptyDir: {}
- name: podinfo
downwardAPI:
items:
- path: annotations
fieldRef:
fieldPath: metadata.annotations
- name: avassa-secrets
emptyDir:
medium: Memory
containers:
- name: nginx
image: nginx
volumeMounts:
- name: shared-data
mountPath: /usr/share/nginx/html
- name: avassa-secrets
mountPath: /avassa/secrets
initContainers:
- name: init-avassa-secrets
image: avassa-mount-secrets:0.1
imagePullPolicy: Never
volumeMounts:
- name: podinfo
mountPath: /avassa/podinfo
- name: avassa-secrets
mountPath: /avassa/secrets
hostNetwork: false
dnsPolicy: Default
Populate Kubernetes Secret
Populate a Kubernetes Secret in a Kubernetes Init container.
apiVersion: v1
kind: Pod
metadata:
name: auth-demo-2
annotations:
avassa.io/api-host: api.theater-operation.avassa.io
avassa.io/tenant: theater-operation
avassa.io/service: theater-ops
avassa.io/role: theater-ops-role
avassa.io/ca-cert: |-
-----BEGIN CERTIFICATE-----
MIICGDCCAb+gAwIBAgISTk4CwNh068Jmvz45tgEmXsk7MAoGCCqGSM49BAMCMGMx
GDAWBgNVBAMTD0F2YXNzYSBBUEkgcm9vdDESMBAGA1UEBxMJU3RvY2tob2xtMQsw
CQYDVQQGEwJTRTEPMA0GA1UEChMGQXZhc3NhMRUwEwYDVQQLEwxkaXN0cmlidXRp
b24wIhgPMjAyMjA0MjEwNzI4MTBaGA8yMDI1MDgzMDExMDQxMFowYzEYMBYGA1UE
AxMPQXZhc3NhIEFQSSByb290MRIwEAYDVQQHEwlTdG9ja2hvbG0xCzAJBgNVBAYT
AlNFMQ8wDQYDVQQKEwZBdmFzc2ExFTATBgNVBAsTDGRpc3RyaWJ1dGlvbjBZMBMG
ByqGSM49AgEGCCqGSM49AwEHA0IABJ6ctcD03qg7jC273SXMi6D4AzLSe/zEEYd6
WnDxgLzpXJTAbchIURSTLGDDMA4AmbjHwcrhXfn1u4iL1sSbhP6jTzBNMA4GA1Ud
DwEB/wQEAwIBhjASBgNVHRMBAf8ECDAGAQH/AgEBMCcGA1UdHwQgMB4wHKAaoBiG
Fmh0dHA6Ly9jcmwuYXZhc3NhLm5ldC8wCgYIKoZIzj0EAwIDRwAwRAIgYY2gpw8f
w5y+6PW92w+lfKgwz5lzniP3IPbZqFi3qGcCIDEU+8lYtp/EG53QFxjqT1cco5D0
9XKqQ/8Vp/8BEg+i
-----END CERTIFICATE-----
avassa.io/k8s-secrets: db-credentials
spec:
serviceAccountName: nginx-sa
volumes:
- name: podinfo
downwardAPI:
items:
- path: annotations
fieldRef:
fieldPath: metadata.annotations
containers:
- name: alpine
image: alpine
command:
- /bin/sh
- "-c"
- "sleep 60m"
env:
- name: DB_USERNAME
valueFrom:
secretKeyRef:
name: db-credentials
key: username
- name: DB_PASSWORD
valueFrom:
secretKeyRef:
name: db-credentials
key: password
initContainers:
- name: init-avassa-secrets
image: avassa-mount-secrets:0.1
imagePullPolicy: Never
volumeMounts:
- name: podinfo
mountPath: /avassa/podinfo
hostNetwork: false
dnsPolicy: Default
Continuous Update
Pre-populate the files user.txt
and password.txt
in an init
container and continue to periodically update the files if
the secrets are changed in Strongbox.
apiVersion: v1
kind: Pod
metadata:
name: auth-demo-3
annotations:
avassa.io/api-host: api.theater-operation.avassa.io
avassa.io/tenant: theater-operation
avassa.io/service: theater-ops
avassa.io/role: theater-ops-role
avassa.io/ca-cert: |-
-----BEGIN CERTIFICATE-----
MIICGDCCAb+gAwIBAgISTk4CwNh068Jmvz45tgEmXsk7MAoGCCqGSM49BAMCMGMx
GDAWBgNVBAMTD0F2YXNzYSBBUEkgcm9vdDESMBAGA1UEBxMJU3RvY2tob2xtMQsw
CQYDVQQGEwJTRTEPMA0GA1UEChMGQXZhc3NhMRUwEwYDVQQLEwxkaXN0cmlidXRp
b24wIhgPMjAyMjA0MjEwNzI4MTBaGA8yMDI1MDgzMDExMDQxMFowYzEYMBYGA1UE
AxMPQXZhc3NhIEFQSSByb290MRIwEAYDVQQHEwlTdG9ja2hvbG0xCzAJBgNVBAYT
AlNFMQ8wDQYDVQQKEwZBdmFzc2ExFTATBgNVBAsTDGRpc3RyaWJ1dGlvbjBZMBMG
ByqGSM49AgEGCCqGSM49AwEHA0IABJ6ctcD03qg7jC273SXMi6D4AzLSe/zEEYd6
WnDxgLzpXJTAbchIURSTLGDDMA4AmbjHwcrhXfn1u4iL1sSbhP6jTzBNMA4GA1Ud
DwEB/wQEAwIBhjASBgNVHRMBAf8ECDAGAQH/AgEBMCcGA1UdHwQgMB4wHKAaoBiG
Fmh0dHA6Ly9jcmwuYXZhc3NhLm5ldC8wCgYIKoZIzj0EAwIDRwAwRAIgYY2gpw8f
w5y+6PW92w+lfKgwz5lzniP3IPbZqFi3qGcCIDEU+8lYtp/EG53QFxjqT1cco5D0
9XKqQ/8Vp/8BEg+i
-----END CERTIFICATE-----
avassa.io/vault.credentials.oper.user: user.txt
avassa.io/vault.credentials.oper.password: password.txt
spec:
serviceAccountName: nginx-sa
volumes:
- name: avassa-secrets
emptyDir:
medium: Memory
- name: podinfo
downwardAPI:
items:
- path: annotations
fieldRef:
fieldPath: metadata.annotations
containers:
- name: alpine
image: alpine
command:
- /bin/sh
- "-c"
- "sleep 60m"
volumeMounts:
- name: avassa-secrets
mountPath: /avassa/secrets
- name: avassa-secrets
image: avassa-mount-secrets:0.1
imagePullPolicy: Never
volumeMounts:
- name: podinfo
mountPath: /avassa/podinfo
- name: avassa-secrets
mountPath: /avassa/secrets
env:
- name: AVASSA_MODE
value: application
- name: AVASSA_UPDATE_INTERVAL
value: 10s
initContainers:
- name: init-avassa-secrets
image: avassa-mount-secrets:0.1
imagePullPolicy: Never
volumeMounts:
- name: podinfo
mountPath: /avassa/podinfo
- name: avassa-secrets
mountPath: /avassa/secrets
env:
- name: AVASSA_MODE
value: init
hostNetwork: false
dnsPolicy: Default
Troubleshooting
The avassa-mount-secrets
container logs to stdout. These logs
can be inspected for errors using the kubectl
command.
For example, in a pod called auth-demo
the output from the
init-avassa-secrets
container can be view using the
following command
kubctl logs auth-demo -c init-avassa-secrets