1Password / kubernetes-secrets-injector

MIT License
53 stars 7 forks source link

1Password Secrets Injector for Kubernetes

The 1Password Secrets Injector implements a mutating webhook to inject 1Password secrets as environment variables into a Kubernetes pod or deployment. Unlike the 1Password Kubernetes Operator, the Secrets Injector doesn't create a Kubernetes Secret when assigning secrets to your resource.

The 1Password Secrets Injector for Kubernetes can use 1Password Connect or 1Password Service Accounts to retrieve items.

Read more on the 1Password Developer Portal.

Usage

# client-deployment.yaml - The client deployment/pod where you want to inject secrets

apiVersion: apps/v1
kind: Deployment
metadata:
  name: app-example
spec:
  selector:
    matchLabels:
      app: app-example
  template:
    metadata:
      annotations:
        operator.1password.io/inject: "app-example1"
      labels:
        app: app-example
    spec:
      containers:
        - name: app-example1
          image: my-image
          ports:
            - containerPort: 5000
          command: ["npm"]
          args: ["start"]
          # A 1Password Connect server will inject secrets into this application.
          env:
          - name: OP_CONNECT_HOST
            value: http://onepassword-connect:8080
          - name: OP_CONNECT_TOKEN
            valueFrom:
              secretKeyRef:
                name: connect-token
                key: token
          - name: DB_USERNAME
            value: op://my-vault/my-item/sql/username
          - name: DB_PASSWORD
            value: op://my-vault/my-item/sql/password

        - name: my-app # my-app isn't listed in the inject annotation above, so secrets won't be injected into this container.
          image: my-image
          ports:
            - containerPort: 5000
          command: ["npm"]
          args: ["start"]
          env:
          - name: DB_USERNAME
            value: op://my-vault/my-item/sql/username
          - name: DB_PASSWORD
            value: op://my-vault/my-item/sql/password
Usage with 1Password Service Accounts ```yaml # client-deployment.yaml - The client deployment/pod where you want to inject secrets apiVersion: apps/v1 kind: Deployment metadata: name: app-example spec: selector: matchLabels: app: app-example template: metadata: annotations: operator.1password.io/inject: "app-example1" operator.1password.io/version: "2-beta" labels: app: app-example spec: containers: - name: app-example1 image: my-image ports: - containerPort: 5000 command: ["npm"] args: ["start"] # A 1Password Service Account will inject secrets into this application. env: - name: OP_SERVICE_ACCOUNT_TOKEN valueFrom: secretKeyRef: name: op-service-account key: token - name: DB_USERNAME value: op://my-vault/my-item/sql/username - name: DB_PASSWORD value: op://my-vault/my-item/sql/password - name: my-app # my-app isn't listed in the inject annotation above, so secrets won't be injected into this container. image: my-image ports: - containerPort: 5000 command: ["npm"] args: ["start"] env: - name: DB_USERNAME value: op://my-vault/my-item/sql/username - name: DB_PASSWORD value: op://my-vault/my-item/sql/password ```

To inject secrets, the Pod you're looking to inject into must have a command value defined in its Deployment or Pod spec. The 1Password Secrets Injector works by mutating the this value on initilization, and as such a command is needed to be mutated. If the deployments you're using aren't designed to have command specified in the deployment, then the 1Password Kubernetes Operator may be a better fit for your use case.

Note: Injected secrets are available only in the current pod's session. In other words, the secrets will only be accessible for the command listed in the container specification. To access it in any other session, for example using kubectl exec, it's necessary to prepend op run -- to the command.

In the example above the app-example1 container will have injected the DB_USERNAME and DB_PASSWORD values in the session executed by the command npm start.

Another alternative to have the secrets available in all container's sessions is by using the 1Password Kubernetes Operator.

Setup and Deployment

Prerequisites

If you want to use 1Password Connect:

Then, follow instructions to use the Kubernetes Injector.

If you want to use 1Password Service Accounts:

Then, follow instructions to use the Kubernetes Injector with a service account.

Use with 1Password Connect

Step 1: Create a Kubernetes secret containing OP_CONNECT_TOKEN

kubectl create secret generic connect-token --from-literal=token=YOUR_OP_CONNECT_TOKEN

Step 2: Add the secrets-injection=enabled label to the namespace

kubectl label namespace default secrets-injection=enabled

Step 3: Deploy the injector

make deploy

NOTE: The injector creates the TLS certificate required for the webhook to work on the fly when deploying the injector (deployment.yaml). When the injector is removed from the cluster, it will delete the certificate.

Step 4: Annotate your client pod or deployment with inject annotation

Annotate your client pod or deployment spec with operator.1password.io/inject. It expects a comma separated list of the names of the containers that will be mutated and have secrets injected.

# client-deployment.yaml
annotations:
  operator.1password.io/inject: "app-example1"

Step 5: Configure the resource's environment

Add an environment variable to the resource with a value referencing your 1Password item. Use the following secret reference syntax: op://<vault>/<item>[/section]/<field>.

env:
  - name: DB_USERNAME
    value: op://my-vault/my-item/sql/username

Step 6: Provide 1Password CLI credentials on your pod or deployment

Provide your Pod or Deployment with 1Password CLI credentials to perform the injection. One possibility to safely provide these credentials is to create a Kubernetes Secret and refer to it in your deployment configuration.

# your-app-pod/deployment.yaml
env:
  - name: OP_CONNECT_HOST
    value: http://onepassword-connect:8080
  - name: OP_CONNECT_TOKEN
    valueFrom:
      secretKeyRef:
        name: connect-token
        key: token
  - name: DB_USERNAME
    value: op://my-vault/my-item/sql/username

Use with 1Password Service Accounts

Step 1: Create a Kubernetes secret containing OP_SERVICE_ACCOUNT_TOKEN

kubectl create secret generic op-service-account --from-literal=token=YOUR_OP_SERVICE_ACCOUNT_TOKEN

Step 2: Add the label secrets-injection=enabled label to the namespace

kubectl label namespace default secrets-injection=enabled

Step 3: Deploy injector

make deploy

NOTE: The injector creates the TLS certificate required for the webhook to work on the fly when deploying the injector (deployment.yaml). When the injector is removed from the cluster, it will delete the certificate.

Step 4: Annotate your client pod or deployment with inject annotation

Annotate your client pod or deployment spec with operator.1password.io/inject. It expects a comma separated list of the names of the containers that will be mutated and have secrets injected.

# client-deployment.yaml
annotations:
  operator.1password.io/inject: "app-example1"

Step 5: Annotate your client pod or deployment with version annotation

Annotate your client pod or deployment with the latest version of the 1Password CLI (2.18.0 or later).

# client-deployment.yaml
annotations:
  operator.1password.io/version: "2-beta"

Step 6: Configure the resource's environment

Add an environment variable to the resource with a value referencing your 1Password item. Use the following secret reference syntax: op://<vault>/<item>[/section]/<field>.

# client-deployment.yaml
env:
  - name: DB_USERNAME
    value: op://my-vault/my-item/sql/username

Step 7: Provide 1Password CLI credentials on your pod or deployment

Provide your Pod or Deployment with 1Password CLI credentials to perform the injection. One possibility to safely provide these secrets is to create a Kubernetes Secret and refer to it in your deployment configuration.

# client-deployment.yaml
env:
  - name: OP_SERVICE_ACCOUNT_TOKEN
    valueFrom:
      secretKeyRef:
        name: op-service-account
        key: token
  - name: DB_USERNAME
    value: op://my-vault/my-item/sql/username

Troubleshooting

If you can't inject secrets in your pod, make sure:

Security

1Password requests you practice responsible disclosure if you discover a vulnerability.

Please file requests through BugCrowd

For information about our security practices, please visit the 1Password Security homepage.