Providing sensitive data to pods by using an external secrets store

Some applications need sensitive information, such as passwords and user names, that you do not want developers to have.

As an alternative to using Kubernetes Secret objects to provide sensitive information, you can use an external secrets store to store the sensitive information. You can use the Secrets Store CSI Driver Operator to integrate with an external secrets store and mount the secret content as a pod volume.

The Secrets Store CSI Driver Operator is a Technology Preview feature only. Technology Preview features are not supported with Red Hat production service level agreements (SLAs) and might not be functionally complete. Red Hat does not recommend using them in production. These features provide early access to upcoming product features, enabling customers to test functionality and provide feedback during the development process.

For more information about the support scope of Red Hat Technology Preview features, see Technology Preview Features Support Scope.

About the Secrets Store CSI Driver Operator

Kubernetes secrets are stored with Base64 encoding. etcd provides encryption at rest for these secrets, but when secrets are retrieved, they are decrypted and presented to the user. If role-based access control is not configured properly on your cluster, anyone with API or etcd access can retrieve or modify a secret. Additionally, anyone who is authorized to create a pod in a namespace can use that access to read any secret in that namespace.

To store and manage your secrets securely, you can configure the OKD Secrets Store Container Storage Interface (CSI) Driver Operator to mount secrets from an external secret management system, such as Azure Key Vault, by using a provider plugin. Applications can then use the secret, but the secret does not persist on the system after the application pod is destroyed.

The Secrets Store CSI Driver Operator, secrets-store.csi.k8s.io, enables OKD to mount multiple secrets, keys, and certificates stored in enterprise-grade external secrets stores into pods as a volume. The Secrets Store CSI Driver Operator communicates with the provider using gRPC to fetch the mount contents from the specified external secrets store. After the volume is attached, the data in it is mounted into the container’s file system. Secrets store volumes are mounted in-line.

Secrets store providers

The following secrets store providers are available for use with the Secrets Store CSI Driver Operator:

  • AWS Secrets Manager

  • AWS Systems Manager Parameter Store

  • Azure Key Vault

Automatic rotation

The Secrets Store CSI driver periodically rotates the content in the mounted volume with the content from the external secrets store. If a secret is updated in the external secrets store, the secret will be updated in the mounted volume. The Secrets Store CSI Driver Operator polls for updates every 2 minutes.

If you enabled synchronization of mounted content as Kubernetes secrets, the Kubernetes secrets are also rotated.

Applications consuming the secret data must watch for updates to the secrets.

Installing the Secrets Store CSI driver

Prerequisites

  • Access to the OKD web console.

  • Administrator access to the cluster.

Procedure

To install the Secrets Store CSI driver:

  1. Install the Secrets Store CSI Driver Operator:

    1. Log in to the web console.

    2. Click OperatorsOperatorHub.

    3. Locate the Secrets Store CSI Driver Operator by typing “Secrets Store CSI” in the filter box.

    4. Click the Secrets Store CSI Driver Operator button.

    5. On the Secrets Store CSI Driver Operator page, click Install.

    6. On the Install Operator page, ensure that:

      • All namespaces on the cluster (default) is selected.

      • Installed Namespace is set to openshift-cluster-csi-drivers.

    7. Click Install.

      After the installation finishes, the Secrets Store CSI Driver Operator is listed in the Installed Operators section of the web console.

  2. Create the ClusterCSIDriver instance for the driver (secrets-store.csi.k8s.io):

    1. Click AdministrationCustomResourceDefinitionsClusterCSIDriver.

    2. On the Instances tab, click Create ClusterCSIDriver.

      Use the following YAML file:

      1. apiVersion: operator.openshift.io/v1
      2. kind: ClusterCSIDriver
      3. metadata:
      4. name: secrets-store.csi.k8s.io
      5. spec:
      6. managementState: Managed
    3. Click Create.

Mounting secrets from an external secrets store to a CSI volume

After installing the Secrets Store CSI Driver Operator, you can mount secrets from one of the following external secrets stores to a CSI volume:

Mounting secrets from AWS Secrets Manager

You can use the Secrets Store CSI Driver Operator to mount secrets from AWS Secrets Manager to a CSI volume in OKD. To mount secrets from AWS Secrets Manager, your cluster must be installed on AWS and use AWS Security Token Service (STS).

It is not supported to use the Secrets Store CSI Driver Operator with AWS Secrets Manager in a hosted control plane cluster.

Prerequisites

  • Your cluster is installed on AWS and uses AWS Security Token Service (STS).

  • You have installed the Secrets Store CSI Driver Operator. See Installing the Secrets Store CSI driver for instructions.

  • You have configured AWS Secrets Manager to store the required secrets.

  • You have extracted and prepared the ccoctl binary.

  • You have installed the jq CLI tool.

  • You have access to the cluster as a user with the cluster-admin role.

Procedure

  1. Install the AWS Secrets Manager provider:

    1. Create a YAML file with the following configuration for the provider resources:

      The AWS Secrets Manager provider for the Secrets Store CSI driver is an upstream provider.

      This configuration is modified from the configuration provided in the upstream AWS documentation so that it works properly with OKD. Changes to this configuration might impact functionality.

      Example aws-provider.yaml file

      1. apiVersion: v1
      2. kind: ServiceAccount
      3. metadata:
      4. name: csi-secrets-store-provider-aws
      5. namespace: openshift-cluster-csi-drivers
      6. ---
      7. apiVersion: rbac.authorization.k8s.io/v1
      8. kind: ClusterRole
      9. metadata:
      10. name: csi-secrets-store-provider-aws-cluster-role
      11. rules:
      12. - apiGroups: [""]
      13. resources: ["serviceaccounts/token"]
      14. verbs: ["create"]
      15. - apiGroups: [""]
      16. resources: ["serviceaccounts"]
      17. verbs: ["get"]
      18. - apiGroups: [""]
      19. resources: ["pods"]
      20. verbs: ["get"]
      21. - apiGroups: [""]
      22. resources: ["nodes"]
      23. verbs: ["get"]
      24. ---
      25. apiVersion: rbac.authorization.k8s.io/v1
      26. kind: ClusterRoleBinding
      27. metadata:
      28. name: csi-secrets-store-provider-aws-cluster-rolebinding
      29. roleRef:
      30. apiGroup: rbac.authorization.k8s.io
      31. kind: ClusterRole
      32. name: csi-secrets-store-provider-aws-cluster-role
      33. subjects:
      34. - kind: ServiceAccount
      35. name: csi-secrets-store-provider-aws
      36. namespace: openshift-cluster-csi-drivers
      37. ---
      38. apiVersion: apps/v1
      39. kind: DaemonSet
      40. metadata:
      41. namespace: openshift-cluster-csi-drivers
      42. name: csi-secrets-store-provider-aws
      43. labels:
      44. app: csi-secrets-store-provider-aws
      45. spec:
      46. updateStrategy:
      47. type: RollingUpdate
      48. selector:
      49. matchLabels:
      50. app: csi-secrets-store-provider-aws
      51. template:
      52. metadata:
      53. labels:
      54. app: csi-secrets-store-provider-aws
      55. spec:
      56. serviceAccountName: csi-secrets-store-provider-aws
      57. hostNetwork: false
      58. containers:
      59. - name: provider-aws-installer
      60. image: public.ecr.aws/aws-secrets-manager/secrets-store-csi-driver-provider-aws:1.0.r2-50-g5b4aca1-2023.06.09.21.19
      61. imagePullPolicy: Always
      62. args:
      63. - --provider-volume=/etc/kubernetes/secrets-store-csi-providers
      64. resources:
      65. requests:
      66. cpu: 50m
      67. memory: 100Mi
      68. limits:
      69. cpu: 50m
      70. memory: 100Mi
      71. securityContext:
      72. privileged: true
      73. volumeMounts:
      74. - mountPath: "/etc/kubernetes/secrets-store-csi-providers"
      75. name: providervol
      76. - name: mountpoint-dir
      77. mountPath: /var/lib/kubelet/pods
      78. mountPropagation: HostToContainer
      79. tolerations:
      80. - operator: Exists
      81. volumes:
      82. - name: providervol
      83. hostPath:
      84. path: "/etc/kubernetes/secrets-store-csi-providers"
      85. - name: mountpoint-dir
      86. hostPath:
      87. path: /var/lib/kubelet/pods
      88. type: DirectoryOrCreate
      89. nodeSelector:
      90. kubernetes.io/os: linux
    2. Grant privileged access to the csi-secrets-store-provider-aws service account by running the following command:

      1. $ oc adm policy add-scc-to-user privileged -z csi-secrets-store-provider-aws -n openshift-cluster-csi-drivers
    3. Create the provider resources by running the following command:

      1. $ oc apply -f aws-provider.yaml
  2. Grant permission to allow the service account to read the AWS secret object:

    1. Create a directory to contain the credentials request by running the following command:

      1. $ mkdir credentialsrequest-dir-aws
    2. Create a YAML file with the following configuration for the credentials request:

      Example credentialsrequest.yaml file

      1. apiVersion: cloudcredential.openshift.io/v1
      2. kind: CredentialsRequest
      3. metadata:
      4. name: aws-provider-test
      5. namespace: openshift-cloud-credential-operator
      6. spec:
      7. providerSpec:
      8. apiVersion: cloudcredential.openshift.io/v1
      9. kind: AWSProviderSpec
      10. statementEntries:
      11. - action:
      12. - "secretsmanager:GetSecretValue"
      13. - "secretsmanager:DescribeSecret"
      14. effect: Allow
      15. resource: "arn:*:secretsmanager:*:*:secret:testSecret-??????"
      16. secretRef:
      17. name: aws-creds
      18. namespace: my-namespace
      19. serviceAccountNames:
      20. - aws-provider
    3. Retrieve the OIDC provider by running the following command:

      1. $ oc get --raw=/.well-known/openid-configuration | jq -r '.issuer'

      Example output

      1. https://<oidc_provider_name>

      Copy the OIDC provider name <oidc_provider_name> from the output to use in the next step.

    4. Use the ccoctl tool to process the credentials request by running the following command:

      1. $ ccoctl aws create-iam-roles \
      2. --name my-role --region=<aws_region> \
      3. --credentials-requests-dir=credentialsrequest-dir-aws \
      4. --identity-provider-arn arn:aws:iam::<aws_account>:oidc-provider/<oidc_provider_name> --output-dir=credrequests-ccoctl-output

      Example output

      1. 2023/05/15 18:10:34 Role arn:aws:iam::<aws_account_id>:role/my-role-my-namespace-aws-creds created
      2. 2023/05/15 18:10:34 Saved credentials configuration to: credrequests-ccoctl-output/manifests/my-namespace-aws-creds-credentials.yaml
      3. 2023/05/15 18:10:35 Updated Role policy for Role my-role-my-namespace-aws-creds

      Copy the <aws_role_arn> from the output to use in the next step. For example, arn:aws:iam::<aws_account_id>:role/my-role-my-namespace-aws-creds.

    5. Bind the service account with the role ARN by running the following command:

      1. $ oc annotate -n my-namespace sa/aws-provider eks.amazonaws.com/role-arn="<aws_role_arn>"
  3. Create a secret provider class to define your secrets store provider:

    1. Create a YAML file that defines the SecretProviderClass object:

      Example secret-provider-class-aws.yaml

      1. apiVersion: secrets-store.csi.x-k8s.io/v1
      2. kind: SecretProviderClass
      3. metadata:
      4. name: my-aws-provider (1)
      5. namespace: my-namespace (2)
      6. spec:
      7. provider: aws (3)
      8. parameters: (4)
      9. objects: |
      10. - objectName: "testSecret"
      11. objectType: "secretsmanager"
      1Specify the name for the secret provider class.
      2Specify the namespace for the secret provider class.
      3Specify the provider as aws.
      4Specify the provider-specific configuration parameters.
    2. Create the SecretProviderClass object by running the following command:

      1. $ oc create -f secret-provider-class-aws.yaml
  4. Create a deployment to use this secret provider class:

    1. Create a YAML file that defines the Deployment object:

      Example deployment.yaml

      1. apiVersion: apps/v1
      2. kind: Deployment
      3. metadata:
      4. name: my-aws-deployment (1)
      5. namespace: my-namespace (2)
      6. spec:
      7. replicas: 1
      8. selector:
      9. matchLabels:
      10. app: my-storage
      11. template:
      12. metadata:
      13. labels:
      14. app: my-storage
      15. spec:
      16. containers:
      17. - name: busybox
      18. image: k8s.gcr.io/e2e-test-images/busybox:1.29
      19. command:
      20. - "/bin/sleep"
      21. - "10000"
      22. volumeMounts:
      23. - name: secrets-store-inline
      24. mountPath: "/mnt/secrets-store"
      25. readOnly: true
      26. volumes:
      27. - name: secrets-store-inline
      28. csi:
      29. driver: secrets-store.csi.k8s.io
      30. readOnly: true
      31. volumeAttributes:
      32. secretProviderClass: "my-aws-provider" (3)
      1Specify the name for the deployment.
      2Specify the namespace for the deployment. This must be the same namespace as the secret provider class.
      3Specify the name of the secret provider class.
    2. Create the Deployment object by running the following command:

      1. $ oc create -f deployment.yaml

Verification

  • Verify that you can access the secrets from AWS Secrets Manager in the pod volume mount:

    1. List the secrets in the pod mount:

      1. $ oc exec busybox-<hash> -n my-namespace -- ls /mnt/secrets-store/

      Example output

      1. testSecret
    2. View a secret in the pod mount:

      1. $ oc exec busybox-<hash> -n my-namespace -- cat /mnt/secrets-store/testSecret

      Example output

      1. <secret_value>

Additional resources

Mounting secrets from AWS Systems Manager Parameter Store

You can use the Secrets Store CSI Driver Operator to mount secrets from AWS Systems Manager Parameter Store to a CSI volume in OKD. To mount secrets from AWS Systems Manager Parameter Store, your cluster must be installed on AWS and use AWS Security Token Service (STS).

It is not supported to use the Secrets Store CSI Driver Operator with AWS Systems Manager Parameter Store in a hosted control plane cluster.

Prerequisites

  • Your cluster is installed on AWS and uses AWS Security Token Service (STS).

  • You have installed the Secrets Store CSI Driver Operator. See Installing the Secrets Store CSI driver for instructions.

  • You have configured AWS Systems Manager Parameter Store to store the required secrets.

  • You have extracted and prepared the ccoctl binary.

  • You have installed the jq CLI tool.

  • You have access to the cluster as a user with the cluster-admin role.

Procedure

  1. Install the AWS Systems Manager Parameter Store provider:

    1. Create a YAML file with the following configuration for the provider resources:

      The AWS Systems Manager Parameter Store provider for the Secrets Store CSI driver is an upstream provider.

      This configuration is modified from the configuration provided in the upstream AWS documentation so that it works properly with OKD. Changes to this configuration might impact functionality.

      Example aws-provider.yaml file

      1. apiVersion: v1
      2. kind: ServiceAccount
      3. metadata:
      4. name: csi-secrets-store-provider-aws
      5. namespace: openshift-cluster-csi-drivers
      6. ---
      7. apiVersion: rbac.authorization.k8s.io/v1
      8. kind: ClusterRole
      9. metadata:
      10. name: csi-secrets-store-provider-aws-cluster-role
      11. rules:
      12. - apiGroups: [""]
      13. resources: ["serviceaccounts/token"]
      14. verbs: ["create"]
      15. - apiGroups: [""]
      16. resources: ["serviceaccounts"]
      17. verbs: ["get"]
      18. - apiGroups: [""]
      19. resources: ["pods"]
      20. verbs: ["get"]
      21. - apiGroups: [""]
      22. resources: ["nodes"]
      23. verbs: ["get"]
      24. ---
      25. apiVersion: rbac.authorization.k8s.io/v1
      26. kind: ClusterRoleBinding
      27. metadata:
      28. name: csi-secrets-store-provider-aws-cluster-rolebinding
      29. roleRef:
      30. apiGroup: rbac.authorization.k8s.io
      31. kind: ClusterRole
      32. name: csi-secrets-store-provider-aws-cluster-role
      33. subjects:
      34. - kind: ServiceAccount
      35. name: csi-secrets-store-provider-aws
      36. namespace: openshift-cluster-csi-drivers
      37. ---
      38. apiVersion: apps/v1
      39. kind: DaemonSet
      40. metadata:
      41. namespace: openshift-cluster-csi-drivers
      42. name: csi-secrets-store-provider-aws
      43. labels:
      44. app: csi-secrets-store-provider-aws
      45. spec:
      46. updateStrategy:
      47. type: RollingUpdate
      48. selector:
      49. matchLabels:
      50. app: csi-secrets-store-provider-aws
      51. template:
      52. metadata:
      53. labels:
      54. app: csi-secrets-store-provider-aws
      55. spec:
      56. serviceAccountName: csi-secrets-store-provider-aws
      57. hostNetwork: false
      58. containers:
      59. - name: provider-aws-installer
      60. image: public.ecr.aws/aws-secrets-manager/secrets-store-csi-driver-provider-aws:1.0.r2-50-g5b4aca1-2023.06.09.21.19
      61. imagePullPolicy: Always
      62. args:
      63. - --provider-volume=/etc/kubernetes/secrets-store-csi-providers
      64. resources:
      65. requests:
      66. cpu: 50m
      67. memory: 100Mi
      68. limits:
      69. cpu: 50m
      70. memory: 100Mi
      71. securityContext:
      72. privileged: true
      73. volumeMounts:
      74. - mountPath: "/etc/kubernetes/secrets-store-csi-providers"
      75. name: providervol
      76. - name: mountpoint-dir
      77. mountPath: /var/lib/kubelet/pods
      78. mountPropagation: HostToContainer
      79. tolerations:
      80. - operator: Exists
      81. volumes:
      82. - name: providervol
      83. hostPath:
      84. path: "/etc/kubernetes/secrets-store-csi-providers"
      85. - name: mountpoint-dir
      86. hostPath:
      87. path: /var/lib/kubelet/pods
      88. type: DirectoryOrCreate
      89. nodeSelector:
      90. kubernetes.io/os: linux
    2. Grant privileged access to the csi-secrets-store-provider-aws service account by running the following command:

      1. $ oc adm policy add-scc-to-user privileged -z csi-secrets-store-provider-aws -n openshift-cluster-csi-drivers
    3. Create the provider resources by running the following command:

      1. $ oc apply -f aws-provider.yaml
  2. Grant permission to allow the service account to read the AWS secret object:

    1. Create a directory to contain the credentials request by running the following command:

      1. $ mkdir credentialsrequest-dir-aws
    2. Create a YAML file with the following configuration for the credentials request:

      Example credentialsrequest.yaml file

      1. apiVersion: cloudcredential.openshift.io/v1
      2. kind: CredentialsRequest
      3. metadata:
      4. name: aws-provider-test
      5. namespace: openshift-cloud-credential-operator
      6. spec:
      7. providerSpec:
      8. apiVersion: cloudcredential.openshift.io/v1
      9. kind: AWSProviderSpec
      10. statementEntries:
      11. - action:
      12. - "ssm:GetParameter"
      13. - "ssm:GetParameters"
      14. effect: Allow
      15. resource: "arn:*:ssm:*:*:parameter/testParameter*"
      16. secretRef:
      17. name: aws-creds
      18. namespace: my-namespace
      19. serviceAccountNames:
      20. - aws-provider
    3. Retrieve the OIDC provider by running the following command:

      1. $ oc get --raw=/.well-known/openid-configuration | jq -r '.issuer'

      Example output

      1. https://<oidc_provider_name>

      Copy the OIDC provider name <oidc_provider_name> from the output to use in the next step.

    4. Use the ccoctl tool to process the credentials request by running the following command:

      1. $ ccoctl aws create-iam-roles \
      2. --name my-role --region=<aws_region> \
      3. --credentials-requests-dir=credentialsrequest-dir-aws \
      4. --identity-provider-arn arn:aws:iam::<aws_account>:oidc-provider/<oidc_provider_name> --output-dir=credrequests-ccoctl-output

      Example output

      1. 2023/05/15 18:10:34 Role arn:aws:iam::<aws_account_id>:role/my-role-my-namespace-aws-creds created
      2. 2023/05/15 18:10:34 Saved credentials configuration to: credrequests-ccoctl-output/manifests/my-namespace-aws-creds-credentials.yaml
      3. 2023/05/15 18:10:35 Updated Role policy for Role my-role-my-namespace-aws-creds

      Copy the <aws_role_arn> from the output to use in the next step. For example, arn:aws:iam::<aws_account_id>:role/my-role-my-namespace-aws-creds.

    5. Bind the service account with the role ARN by running the following command:

      1. $ oc annotate -n my-namespace sa/aws-provider eks.amazonaws.com/role-arn="<aws_role_arn>"
  3. Create a secret provider class to define your secrets store provider:

    1. Create a YAML file that defines the SecretProviderClass object:

      Example secret-provider-class-aws.yaml

      1. apiVersion: secrets-store.csi.x-k8s.io/v1
      2. kind: SecretProviderClass
      3. metadata:
      4. name: my-aws-provider (1)
      5. namespace: my-namespace (2)
      6. spec:
      7. provider: aws (3)
      8. parameters: (4)
      9. objects: |
      10. - objectName: "testParameter"
      11. objectType: "ssmparameter"
      1Specify the name for the secret provider class.
      2Specify the namespace for the secret provider class.
      3Specify the provider as aws.
      4Specify the provider-specific configuration parameters.
    2. Create the SecretProviderClass object by running the following command:

      1. $ oc create -f secret-provider-class-aws.yaml
  4. Create a deployment to use this secret provider class:

    1. Create a YAML file that defines the Deployment object:

      Example deployment.yaml

      1. apiVersion: apps/v1
      2. kind: Deployment
      3. metadata:
      4. name: my-aws-deployment (1)
      5. namespace: my-namespace (2)
      6. spec:
      7. replicas: 1
      8. selector:
      9. matchLabels:
      10. app: my-storage
      11. template:
      12. metadata:
      13. labels:
      14. app: my-storage
      15. spec:
      16. containers:
      17. - name: busybox
      18. image: k8s.gcr.io/e2e-test-images/busybox:1.29
      19. command:
      20. - "/bin/sleep"
      21. - "10000"
      22. volumeMounts:
      23. - name: secrets-store-inline
      24. mountPath: "/mnt/secrets-store"
      25. readOnly: true
      26. volumes:
      27. - name: secrets-store-inline
      28. csi:
      29. driver: secrets-store.csi.k8s.io
      30. readOnly: true
      31. volumeAttributes:
      32. secretProviderClass: "my-aws-provider" (3)
      1Specify the name for the deployment.
      2Specify the namespace for the deployment. This must be the same namespace as the secret provider class.
      3Specify the name of the secret provider class.
    2. Create the Deployment object by running the following command:

      1. $ oc create -f deployment.yaml

Verification

  • Verify that you can access the secrets from AWS Systems Manager Parameter Store in the pod volume mount:

    1. List the secrets in the pod mount:

      1. $ oc exec busybox-<hash> -n my-namespace -- ls /mnt/secrets-store/

      Example output

      1. testParameter
    2. View a secret in the pod mount:

      1. $ oc exec busybox-<hash> -n my-namespace -- cat /mnt/secrets-store/testSecret

      Example output

      1. <secret_value>

Additional resources

Mounting secrets from Azure Key Vault

You can use the Secrets Store CSI Driver Operator to mount secrets from Azure Key Vault to a CSI volume in OKD. To mount secrets from Azure Key Vault, your cluster must be installed on Microsoft Azure.

Prerequisites

  • Your cluster is installed on Azure.

  • You have installed the Secrets Store CSI Driver Operator. See Installing the Secrets Store CSI driver for instructions.

  • You have configured Azure Key Vault to store the required secrets.

  • You have installed the Azure CLI (az).

  • You have access to the cluster as a user with the cluster-admin role.

Procedure

  1. Install the Azure Key Vault provider:

    1. Create a YAML file with the following configuration for the provider resources:

      The Azure Key Vault provider for the Secrets Store CSI driver is an upstream provider.

      This configuration is modified from the configuration provided in the upstream Azure documentation so that it works properly with OKD. Changes to this configuration might impact functionality.

      Example azure-provider.yaml file

      1. apiVersion: v1
      2. kind: ServiceAccount
      3. metadata:
      4. name: csi-secrets-store-provider-azure
      5. namespace: openshift-cluster-csi-drivers
      6. ---
      7. apiVersion: rbac.authorization.k8s.io/v1
      8. kind: ClusterRole
      9. metadata:
      10. name: csi-secrets-store-provider-azure-cluster-role
      11. rules:
      12. - apiGroups: [""]
      13. resources: ["serviceaccounts/token"]
      14. verbs: ["create"]
      15. - apiGroups: [""]
      16. resources: ["serviceaccounts"]
      17. verbs: ["get"]
      18. - apiGroups: [""]
      19. resources: ["pods"]
      20. verbs: ["get"]
      21. - apiGroups: [""]
      22. resources: ["nodes"]
      23. verbs: ["get"]
      24. ---
      25. apiVersion: rbac.authorization.k8s.io/v1
      26. kind: ClusterRoleBinding
      27. metadata:
      28. name: csi-secrets-store-provider-azure-cluster-rolebinding
      29. roleRef:
      30. apiGroup: rbac.authorization.k8s.io
      31. kind: ClusterRole
      32. name: csi-secrets-store-provider-azure-cluster-role
      33. subjects:
      34. - kind: ServiceAccount
      35. name: csi-secrets-store-provider-azure
      36. namespace: openshift-cluster-csi-drivers
      37. ---
      38. apiVersion: apps/v1
      39. kind: DaemonSet
      40. metadata:
      41. namespace: openshift-cluster-csi-drivers
      42. name: csi-secrets-store-provider-azure
      43. labels:
      44. app: csi-secrets-store-provider-azure
      45. spec:
      46. updateStrategy:
      47. type: RollingUpdate
      48. selector:
      49. matchLabels:
      50. app: csi-secrets-store-provider-azure
      51. template:
      52. metadata:
      53. labels:
      54. app: csi-secrets-store-provider-azure
      55. spec:
      56. serviceAccountName: csi-secrets-store-provider-azure
      57. hostNetwork: true
      58. containers:
      59. - name: provider-azure-installer
      60. image: mcr.microsoft.com/oss/azure/secrets-store/provider-azure:v1.4.1
      61. imagePullPolicy: IfNotPresent
      62. args:
      63. - --endpoint=unix:///provider/azure.sock
      64. - --construct-pem-chain=true
      65. - --healthz-port=8989
      66. - --healthz-path=/healthz
      67. - --healthz-timeout=5s
      68. livenessProbe:
      69. httpGet:
      70. path: /healthz
      71. port: 8989
      72. failureThreshold: 3
      73. initialDelaySeconds: 5
      74. timeoutSeconds: 10
      75. periodSeconds: 30
      76. resources:
      77. requests:
      78. cpu: 50m
      79. memory: 100Mi
      80. limits:
      81. cpu: 50m
      82. memory: 100Mi
      83. securityContext:
      84. allowPrivilegeEscalation: false
      85. readOnlyRootFilesystem: true
      86. runAsUser: 0
      87. capabilities:
      88. drop:
      89. - ALL
      90. volumeMounts:
      91. - mountPath: "/provider"
      92. name: providervol
      93. affinity:
      94. nodeAffinity:
      95. requiredDuringSchedulingIgnoredDuringExecution:
      96. nodeSelectorTerms:
      97. - matchExpressions:
      98. - key: type
      99. operator: NotIn
      100. values:
      101. - virtual-kubelet
      102. volumes:
      103. - name: providervol
      104. hostPath:
      105. path: "/var/run/secrets-store-csi-providers"
      106. tolerations:
      107. - operator: Exists
      108. nodeSelector:
      109. kubernetes.io/os: linux
    2. Grant privileged access to the csi-secrets-store-provider-azure service account by running the following command:

      1. $ oc adm policy add-scc-to-user privileged -z csi-secrets-store-provider-azure -n openshift-cluster-csi-drivers
    3. Create the provider resources by running the following command:

      1. $ oc apply -f azure-provider.yaml
  2. Create a service principal to access the key vault:

    1. Set the service principal client secret as an environment variable by running the following command:

      1. $ SERVICE_PRINCIPAL_CLIENT_SECRET="$(az ad sp create-for-rbac --name https://$KEYVAULT_NAME --query 'password' -otsv)"
    2. Set the service principal client ID as an environment variable by running the following command:

      1. $ SERVICE_PRINCIPAL_CLIENT_ID="$(az ad sp list --display-name https://$KEYVAULT_NAME --query '[0].appId' -otsv)"
    3. Create a generic secret with the service principal client secret and ID by running the following command:

      1. $ oc create secret generic secrets-store-creds -n my-namespace --from-literal clientid=${SERVICE_PRINCIPAL_CLIENT_ID} --from-literal clientsecret=${SERVICE_PRINCIPAL_CLIENT_SECRET}
    4. Apply the secrets-store.csi.k8s.io/used=true label to allow the provider to find this nodePublishSecretRef secret:

      1. $ oc -n my-namespace label secret secrets-store-creds secrets-store.csi.k8s.io/used=true
  3. Create a secret provider class to define your secrets store provider:

    1. Create a YAML file that defines the SecretProviderClass object:

      Example secret-provider-class-azure.yaml

      1. apiVersion: secrets-store.csi.x-k8s.io/v1
      2. kind: SecretProviderClass
      3. metadata:
      4. name: my-azure-provider (1)
      5. namespace: my-namespace (2)
      6. spec:
      7. provider: azure (3)
      8. parameters: (4)
      9. usePodIdentity: "false"
      10. useVMManagedIdentity: "false"
      11. userAssignedIdentityID: ""
      12. keyvaultName: "kvname"
      13. objects: |
      14. array:
      15. - |
      16. objectName: secret1
      17. objectType: secret
      18. tenantId: "tid"
      1Specify the name for the secret provider class.
      2Specify the namespace for the secret provider class.
      3Specify the provider as azure.
      4Specify the provider-specific configuration parameters.
    2. Create the SecretProviderClass object by running the following command:

      1. $ oc create -f secret-provider-class-azure.yaml
  4. Create a deployment to use this secret provider class:

    1. Create a YAML file that defines the Deployment object:

      Example deployment.yaml

      1. apiVersion: apps/v1
      2. kind: Deployment
      3. metadata:
      4. name: my-azure-deployment (1)
      5. namespace: my-namespace (2)
      6. spec:
      7. replicas: 1
      8. selector:
      9. matchLabels:
      10. app: my-storage
      11. template:
      12. metadata:
      13. labels:
      14. app: my-storage
      15. spec:
      16. containers:
      17. - name: busybox
      18. image: k8s.gcr.io/e2e-test-images/busybox:1.29
      19. command:
      20. - "/bin/sleep"
      21. - "10000"
      22. volumeMounts:
      23. - name: secrets-store-inline
      24. mountPath: "/mnt/secrets-store"
      25. readOnly: true
      26. volumes:
      27. - name: secrets-store-inline
      28. csi:
      29. driver: secrets-store.csi.k8s.io
      30. readOnly: true
      31. volumeAttributes:
      32. secretProviderClass: "my-azure-provider" (3)
      33. nodePublishSecretRef:
      34. name: secrets-store-creds (4)
      1Specify the name for the deployment.
      2Specify the namespace for the deployment. This must be the same namespace as the secret provider class.
      3Specify the name of the secret provider class.
      4Specify the name of the Kubernetes secret that contains the service principal credentials to access Azure Key Vault.
    2. Create the Deployment object by running the following command:

      1. $ oc create -f deployment.yaml

Verification

  • Verify that you can access the secrets from Azure Key Vault in the pod volume mount:

    1. List the secrets in the pod mount:

      1. $ oc exec busybox-<hash> -n my-namespace -- ls /mnt/secrets-store/

      Example output

      1. secret1
    2. View a secret in the pod mount:

      1. $ oc exec busybox-<hash> -n my-namespace -- cat /mnt/secrets-store/secret1

      Example output

      1. my-secret-value

Enabling synchronization of mounted content as Kubernetes secrets

You can enable synchronization to create Kubernetes secrets from the content on a mounted volume. An example where you might want to enable synchronization is to use an environment variable in your deployment to reference the Kubernetes secret.

Do not enable synchronization if you do not want to store your secrets on your OKD cluster and in etcd. Enable this functionality only if you require it, such as when you want to use environment variables to refer to the secret.

If you enable synchronization, the secrets from the mounted volume are synchronized as Kubernetes secrets after you start a pod that mounts the secrets.

The synchronized Kubernetes secret is deleted when all pods that mounted the content are deleted.

Prerequisites

  • You have installed the Secrets Store CSI Driver Operator.

  • You have installed a secrets store provider.

  • You have created the secret provider class.

  • You have access to the cluster as a user with the cluster-admin role.

Procedure

  1. Edit the SecretProviderClass resource by running the following command:

    1. $ oc edit secretproviderclass my-azure-provider (1)
    1Replace my-azure-provider with the name of your secret provider class.
  2. Add the secretsObjects section with the configuration for the synchronized Kubernetes secrets:

    1. apiVersion: secrets-store.csi.x-k8s.io/v1
    2. kind: SecretProviderClass
    3. metadata:
    4. name: my-azure-provider
    5. namespace: my-namespace
    6. spec:
    7. provider: azure
    8. secretObjects: (1)
    9. - secretName: tlssecret (2)
    10. type: kubernetes.io/tls (3)
    11. labels:
    12. environment: "test"
    13. data:
    14. - objectName: tlskey (4)
    15. key: tls.key (5)
    16. - objectName: tlscrt
    17. key: tls.crt
    18. parameters:
    19. usePodIdentity: "false"
    20. keyvaultName: "kvname"
    21. objects: |
    22. array:
    23. - |
    24. objectName: tlskey
    25. objectType: secret
    26. - |
    27. objectName: tlscrt
    28. objectType: secret
    29. tenantId: "tid"
    1Specify the configuration for synchronized Kubernetes secrets.
    2Specify the name of the Kubernetes Secret object to create.
    3Specify the type of Kubernetes Secret object to create. For example, Opaque or kubernetes.io/tls.
    4Specify the object name or alias of the mounted content to synchronize.
    5Specify the data field from the specified objectName to populate the Kubernetes secret with.
  3. Save the file to apply the changes.

Viewing the status of secrets in the pod volume mount

You can view detailed information, including the versions, of the secrets in the pod volume mount.

The Secrets Store CSI Driver Operator creates a SecretProviderClassPodStatus resource in the same namespace as the pod. You can review this resource to see detailed information, including versions, about the secrets in the pod volume mount.

Prerequisites

  • You have installed the Secrets Store CSI Driver Operator.

  • You have installed a secrets store provider.

  • You have created the secret provider class.

  • You have deployed a pod that mounts a volume from the Secrets Store CSI Driver Operator.

  • You have access to the cluster as a user with the cluster-admin role.

Procedure

  • View detailed information about the secrets in a pod volume mount by running the following command:

    1. $ oc get secretproviderclasspodstatus <secret_provider_class_pod_status_name> -o yaml (1)
    1The name of the secret provider class pod status object is in the format of <pod_name>-<namespace>-<secret_provider_class_name>.

    Example output

    1. ...
    2. status:
    3. mounted: true
    4. objects:
    5. - id: secret/tlscrt
    6. version: f352293b97da4fa18d96a9528534cb33
    7. - id: secret/tlskey
    8. version: 02534bc3d5df481cb138f8b2a13951ef
    9. podName: busybox-<hash>
    10. secretProviderClassName: my-azure-provider
    11. targetPath: /var/lib/kubelet/pods/f0d49c1e-c87a-4beb-888f-37798456a3e7/volumes/kubernetes.io~csi/secrets-store-inline/mount

Uninstalling the Secrets Store CSI Driver Operator

Prerequisites

  • Access to the OKD web console.

  • Administrator access to the cluster.

Procedure

To uninstall the Secrets Store CSI Driver Operator:

  1. Stop all application pods that use the secrets-store.csi.k8s.io provider.

  2. Remove any third-party provider plug-in for your chosen secret store.

  3. Remove the Container Storage Interface (CSI) driver and associated manifests:

    1. Click AdministrationCustomResourceDefinitionsClusterCSIDriver.

    2. On the Instances tab, for secrets-store.csi.k8s.io, on the far left side, click the drop-down menu, and then click Delete ClusterCSIDriver.

    3. When prompted, click Delete.

  4. Verify that the CSI driver pods are no longer running.

  5. Uninstall the Secrets Store CSI Driver Operator:

    Before you can uninstall the Operator, you must remove the CSI driver first.

    1. Click OperatorsInstalled Operators.

    2. On the Installed Operators page, scroll or type “Secrets Store CSI” into the Search by name box to find the Operator, and then click it.

    3. On the upper, right of the Installed Operators > Operator details page, click ActionsUninstall Operator.

    4. When prompted on the Uninstall Operator window, click the Uninstall button to remove the Operator from the namespace. Any applications deployed by the Operator on the cluster need to be cleaned up manually.

      After uninstalling, the Secrets Store CSI Driver Operator is no longer listed in the Installed Operators section of the web console.