oci-secrets-store-csi-driver-provider

Secrets Store CSI Driver Provider for OCI Vault

Provider for OCI Vault allows you to get secrets stored in OCI Vault and mount them into Kubernetes pods via the Secrets Store CSI driver.

The provider is a gRPC server accessible via the Unix domain socket. It’s interface is defined by the Secrets Store CSI driver. Secrets Store CSI Driver requests the provider’s API in order to mount secrets onto the pods.

Table of Contents

End User Usage

This section describes steps to deploy and test solution.

Prerequisites

General

Authentication and Authorization

Currently, two modes of authentication is supported. Some AuthN modes are applicable only for a particular variant of cluster.

User Principal

Prepare user principal configuration to access OCI API as per sample template provided in deploy/example/user-auth-config-example.yaml

Refer these documents to understand the properties: ** Required Keys and OCIDs ** SDK Configuration File.

Create a secret in your cluster and in the same namespace of your workload/application

kubectl create secret generic oci-config \
         --from-file=config=user-auth-config-example.yaml \
         --from-file=private-key=./oci/oci_api_key.pem \
         --namespace <workload-namespace>

Instance Principal

Instance principal would work only on OKE cluster. Access should be granted using Access Policies(See Access Policies section).

Access Policies

Access to the vault and secrets should be explicity granted using Policies in case of Instance principal authencation or other users(non owner of vault) or groups of tenancy in case of user principal authentication.

It involves two steps

Deployment

Provider and Driver would be deployed as Daemonset. kube-system namespace is preferred, but not restricted.

Provider can be deployed in two ways

Helm

helm repo add oci-provider https://oracle.github.io/oci-secrets-store-csi-driver-provider/charts
helm install oci-provider oci-provider/oci-secrets-store-csi-driver-provider --namespace kube-system

From Code Repository

helm upgrade --install  oci-provider -n kube-system charts/oci-secrets-store-csi-driver-provider

Default values are provided in charts/oci-secrets-store-csi-driver-provider/values.yaml file, can be overridden as per the requirement.

Deployment using yamls

Note: Use the correct namespace

kubectl get pods --namespace <namespace> --selector='app.kubernetes.io/name in (oci-secrets-store-csi-driver-provider, secrets-store-csi-driver)'

Workload/Application Deployment

It involves deployment of two resources

SecretProviderClass(SPC)

SecretProviderClass is a kind of link between volume and concrete provider. Basically, it contains:

  1. Name of the provider used to retrieve secrets (spec.provider field).
  2. Enumeration of secrets to mount in a single volume (spec.parameters.secrets field).
  3. OCI VaultId (spec.parameters.vaultId field).
  4. Authentication type used to connect to the OCI Vault (spec.parameters.authType field).
  5. Kubernetes Secret holding user principal auth config in case of user auth principal (spec.parameters.authSecretName field) SecretProviderClass is custom K8S resource provided by Secrets Store CSI driver. It’s definition is created as part of driver deployment.

Check the Usage page from official docs to learn more about SecretProviderClass.

SecretProviderClass structure

apiVersion: secrets-store.csi.x-k8s.io/v1
kind: SecretProviderClass
metadata:
  name: my-test-spc
spec:
  provider: oci 
  parameters: # provider-specific parameters
    secrets: |
      - name: secret1              # Name of the secret in vault
        stage: PREVIOUS
      - name: secret2
        versionNumber: 1           # Version of the secret
        fileName: app1-db-password # Secret will be mounted with this name instead of secret name
    authType: instance             # possible values are: user, instance
    authSecretName: oci-config  # required only for user authType
    vaultId: ocid1.vault.oc1..aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
    

Refer to the sample file provided at deploy/example/secret-provider-class.yaml

Let’s describe the provider-specific parameters section:

  1. Field secrets contains an array of secrets to mount.
  2. Each secret represents OCI secret bundle and could have the next attributes:
    1. name - a user-friendly name for the secret. Secret names are unique within a vault. Secret names are case-sensitive.
    2. stage - the rotation state of the secret version. Allowed values are:
      • CURRENT
      • PENDING
      • LATEST
      • PREVIOUS
      • DEPRECATED
    3. versionNumber - the version number of the secret. Should be a positive number.

    Read OCI Secret Versions and Rotation States for more information about versions and stages.

  3. Each secret could be identified with:
    • name and stage
    • name and versionNumber
    • single attribute name (in this case, the default stage CURRENT is used for identification)
  4. fileName - a user-friendly name for a secret. The secret will be mounted with fileName name instead of secret name.

Workload Deployment

More information is available at Usage : https://secrets-store-csi-driver.sigs.k8s.io/getting-started/usage.html

App Verification

Deploy an app with secrets mounted from OCI Vault(Assuming the default namespace)

  1. Create a secret with correct values for user config. Edit deploy/example/user-auth-config-example.yaml file.
     kubectl create secret generic oci-config \
        --from-file=config=./deploy/example/user-auth-config-example.yaml
    
  2. Adjust SecretProviderClass to enumerate there secrets stored in particular OCI Vault. Edit deploy/example/secret-provider-class.yaml file. Create example SecretProviderClass with enumerated secrets.
     kubectl apply -f deploy/example/secret-provider-class.yaml
    
  3. Create an example app with secrets mounted via SecretProviderClass created above.
     kubectl apply -f deploy/example/app.deployment.yaml
    
  4. Step into the app pod and verify secrets.
     kubectl exec -ti deployment.apps/nginx  -- sh;
     ls /mnt/secrets-store/;
     # let's assume secrets 'foo' and 'hello' were mounted
     cat /mnt/secrets-store/foo;
     cat /mnt/secrets-store/hello;
    

Cleanup

Execute the following to clean up the environment after testing completed:

Additional Features

Secrets Sync

Driver provides Sync as Kubernetes Secret feature. It allows the driver to create a Kubernetes Secret to mirror the mounted content. For example, this feature might be useful for injecting secrets as an environment variables.

Another usecase could be for mounting certificates in the Ingress controller.

By default, the driver has no permission to create K8S secrets. So, to enable secrets sync set Helm value secrets-store-csi-driver.syncSecret.enabled to true. This would enable K8S RBAC role and binding for the driver to allow operations on secrets.

Auto Rotation of Secrets

Driver provides Auto Rotation of mounted contents and synced Kubernetes secret feature. It allows the driver to update mounted secrets as well as Kubernetes secrets periodically in sync with OCI Vault data at the configured rotation frequency.

By default, the driver doesn’t enable auto rotation feature. So, to enable set Helm value secrets-store-csi-driver.enableSecretRotation to true.

The default rotation frequency is 2 minutes. To use custom value, set Helm value secrets-store-csi-driver.rotationPollInterval to some permitted value.

For driver official documentation.

Developer Zone or Custom Build

Build Docker image

docker build -t oci-secrets-store-csi-driver-provider -f build/Dockerfile .

For Mac ARM64, to build for linux/amd64

docker buildx build -t --platform=linux/amd64 oci-secrets-store-csi-driver-provider -f build/Dockerfile .

Dependency management

Module vendoring is used to manage 3d-party modules in the project. vendor/ folder contains all 3d-party modules. All changes to those modules should be reflected in the remote VCS repository.

How to introduce new modules or upgrade existing ones?

  1. Once new modules was added or updated, the next command should be executed:
    go mod vendor
    

    This command will update sources for that module in vendor/ folder.

  2. Then commit those changes.

Versioning

Each build publishes 2 artifacts: Docker image and Helm chart. Both of these artifacts use SemVer 2.0.0 for versioning.

That means that developers must increment both Docker image and Helm chart versions, otherwise, the build will fail:

Note that Docker image version and Helm chart version are independent.

Linter

golangci-lint is used for linting. It is a standalone aggregator for Go linters. Here is the tool’s documentation.

Since this tool is standalone, the developers have to control the version themselves.

NOTE: Current version is 1.46.2

CI Setup

GitHub Actions is used to implement Continuous integration pipeline. Location in the code base: .github/workflows Github workflows:

  1. unit-tests.yaml – Runs unit test cases
    • Functionality:
    • builds binary
    • run unit tests and test coverage reports
    • send report to coveralls
  1. release.yaml – Release
    • Functionality:
    • Tags the docker image with release version
    • Releases helm charts * triggers:
    • on creating a release tag * dependencies:
    • unit-tests.yaml
    • build-n-push.yaml * flow: Release Pipeline

Known Issues

FAQ