kuberneteskubectlkubernetes-secrets

How to list all resource to secret mappings?


I am looking for a kubectl command that will list everywhere a secret is referenced.

Example output:

deploymentABC - secretkeyname1
deploymentXYZ - secretkeyname2
statefulset123 - secretkeyname1

I imagine it could access the env.from.secret.name from the yaml?


Solution

  • For all this complicated queries and if you absolutely want to/only can use kubectl, you can rely on Go templates support.

    First, define the template (e.g. in a file list_secrets.tmpl).

    {{- range .items}}
        {{- $namespaceAndName := (printf "%s\t%s/%s" .kind .metadata.namespace .metadata.name)}}
        {{- range .spec.template.spec.containers}}
            {{- range .envFrom}}
                {{- $namespaceAndName}}{{- " - "}}{{- .secretRef.name}}{{- "\n"}}
            {{- end}}
        {{- end}}
    {{- end}}
    

    This iterates over all envFrom sections of all containers, and display namespace/name - secretRefName if any.

    Then, use that template in kubectl to format your Deployments and StatefulSets. You could technically pass the template like this: --o=gotemplate='{{...]}}', but I found it rather difficult to read, so I'd rather write it in a separate file (but it's just my opinion).

    kubectl get -A deploy,statefulsets -o=go-template-file=list_secrets.tmpl
    

    You should get something like:

    Deployment      default/app1 - secret1
    Deployment      default/app2 - secret1
    StatefulSet     default/app3 - secret1
    StatefulSet     default/app3 - secret3
    

    From there, you can do whatever you want, some examples of what you can achieve below.

    List only Deployments/StatefulSets with a particular secret

    Here, secret1 for example (see {{- if eq .secretRef.name "secret1"}} to check name equality).

    {{- range .items}}
        {{- $namespaceAndName := (printf "%s\t%s/%s" .kind .metadata.namespace .metadata.name)}}
        {{- range .spec.template.spec.containers}}
            {{- range .envFrom}}
                {{- if eq .secretRef.name "secret1"}}
                    {{- $namespaceAndName}}{{- " - "}}{{- .secretRef.name}}{{- "\n"}}
                {{- end}}
            {{- end}}
        {{- end}}
    {{- end}}
    

    Get secrets mounted as volumes

    Here, we have to iterate over volumes rather than containers.

    {{- range .items}}
        {{- $namespaceAndName := (printf "%s\t%s/%s" .kind .metadata.namespace .metadata.name)}}
        {{- range .spec.template.spec.volumes}}
            {{- if .secret }}
                {{- $namespaceAndName}}{{- " - "}}{{- .secret.secretName}}{{- "\n"}}
            {{- end}}
        {{- end}}
    {{- end}}
    

    Get secrets mounted as env vars and volumes

    This is a mix of the previous solutions; we also add details if the secret is used as env vars or volumes.

    {{- range .items}}
        {{- $namespaceAndName := (printf "%s\t%s/%s" .kind .metadata.namespace .metadata.name)}}
        {{- range .spec.template.spec.containers}}
            {{- range .envFrom}}
                {{- $namespaceAndName}}{{- " - "}}{{- .secretRef.name}}{{- " (env)\n"}}
            {{- end}}
        {{- end}}
        {{- range .spec.template.spec.volumes}}
            {{- if .secret }}
                {{- $namespaceAndName}}{{- " - "}}{{- .secret.secretName}}{{- " (volume)\n"}}
            {{- end}}
        {{- end}}
    {{- end}}
    

    This will print:

    Deployment      default/app1 - secret1 (env)
    Deployment      default/app1 - secret1 (volume)
    Deployment      default/app2 - secret1 (env)
    StatefulSet     default/app3 - secret1 (env)
    StatefulSet     default/app3 - secret3 (env)