Skip to main content

CI/CD integration patterns

The standard pattern for Passwork CI/CD integration:

Pipeline runner → passwork-cli exec → deploy/build script with secrets in ENV

Only three Passwork credentials live in the CI/CD platform's own secret storage: PASSWORK_HOST, PASSWORK_TOKEN, and PASSWORK_MASTER_KEY. Everything else — database passwords, API keys, cloud credentials — lives in Passwork and is injected at runtime.


Design principles

One service account per pipeline type

A production deploy pipeline and a staging deploy pipeline should use different service accounts with access to their respective environments. This limits blast radius if a token is leaked.

Read only as the default access level

Grant Read only to all service accounts unless the pipeline explicitly rotates credentials, in which case Read and edit is needed.

Never echo secrets

CI/CD platforms capture stdout and stderr in job logs. Never echo $SECRET or printenv | grep SECRET in pipeline steps. Use secrets only as arguments to commands.

Use folder ID, not item IDs

Structure your vault so a pipeline can use --folder-id to get all its secrets from one place. Hardcoding individual --password-id values is only justified when you need a single specific credential.


GitLab CI

Setup

In Settings → CI/CD → Variables, add (all set to Protected and Masked where applicable):

VariableTypeMasked
PASSWORK_HOSTVariableNo
PASSWORK_TOKENVariableYes
PASSWORK_MASTER_KEYVariableYes
PROD_SECRETS_FOLDER_IDVariableNo
STAGING_SECRETS_FOLDER_IDVariableNo

Basic pipeline

stages:
- deploy

deploy_production:
stage: deploy
image: passwork/passwork-cli:latest
variables:
PASSWORK_HOST: $PASSWORK_HOST
PASSWORK_TOKEN: $PASSWORK_TOKEN
PASSWORK_MASTER_KEY: $PASSWORK_MASTER_KEY
script:
- passwork-cli exec --folder-id "$PROD_SECRETS_FOLDER_ID" ./deploy.sh
environment:
name: production
when: manual
only:
- main

Multi-environment pipeline

.deploy_template: &deploy_template
image: passwork/passwork-cli:latest
variables:
PASSWORK_HOST: $PASSWORK_HOST
PASSWORK_TOKEN: $PASSWORK_TOKEN
PASSWORK_MASTER_KEY: $PASSWORK_MASTER_KEY
script:
- passwork-cli exec --folder-id "$SECRETS_FOLDER_ID" ./deploy.sh

deploy_staging:
<<: *deploy_template
stage: deploy
variables:
SECRETS_FOLDER_ID: $STAGING_SECRETS_FOLDER_ID
environment:
name: staging
only:
- develop

deploy_production:
<<: *deploy_template
stage: deploy
variables:
SECRETS_FOLDER_ID: $PROD_SECRETS_FOLDER_ID
environment:
name: production
when: manual
only:
- main

GitHub Actions

Setup

In Settings → Secrets and variables → Actions:

  • Secrets (encrypted): PASSWORK_HOST, PASSWORK_TOKEN, PASSWORK_MASTER_KEY
  • Variables (plain): PROD_SECRETS_FOLDER_ID, STAGING_SECRETS_FOLDER_ID

Basic workflow

name: Deploy

on:
push:
branches: [main]

jobs:
deploy:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4

- name: Deploy with secrets from Passwork
run: |
docker run --rm \
-e PASSWORK_HOST="${{ secrets.PASSWORK_HOST }}" \
-e PASSWORK_TOKEN="${{ secrets.PASSWORK_TOKEN }}" \
-e PASSWORK_MASTER_KEY="${{ secrets.PASSWORK_MASTER_KEY }}" \
-v ${{ github.workspace }}:/app \
-w /app \
passwork/passwork-cli:latest \
exec --folder-id "${{ vars.PROD_SECRETS_FOLDER_ID }}" ./deploy.sh

Multi-environment workflow

jobs:
deploy:
runs-on: ubuntu-latest
environment: ${{ github.ref == 'refs/heads/main' && 'production' || 'staging' }}
steps:
- uses: actions/checkout@v4

- name: Deploy
run: |
docker run --rm \
-e PASSWORK_HOST="${{ secrets.PASSWORK_HOST }}" \
-e PASSWORK_TOKEN="${{ secrets.PASSWORK_TOKEN }}" \
-e PASSWORK_MASTER_KEY="${{ secrets.PASSWORK_MASTER_KEY }}" \
-v ${{ github.workspace }}:/app \
-w /app \
passwork/passwork-cli:latest \
exec --folder-id "${{ vars.SECRETS_FOLDER_ID }}" ./deploy.sh

Bitbucket Pipelines

image: passwork/passwork-cli:latest

pipelines:
branches:
main:
- step:
name: Deploy to production
deployment: production
script:
- passwork-cli exec --folder-id "$PROD_SECRETS_FOLDER_ID" ./deploy.sh

Configure PASSWORK_HOST, PASSWORK_TOKEN, PASSWORK_MASTER_KEY, and folder IDs in Repository settings → Pipelines → Repository variables (mark the tokens as Secured).


Kubernetes

Init container pattern

An init container fetches secrets before the main application starts and writes them to a shared in-memory volume. The main container reads from that volume.

apiVersion: v1
kind: Pod
metadata:
name: order-service
spec:
initContainers:
- name: fetch-secrets
image: passwork/passwork-cli:latest
env:
- name: PASSWORK_HOST
valueFrom:
secretKeyRef:
name: passwork-credentials
key: host
- name: PASSWORK_TOKEN
valueFrom:
secretKeyRef:
name: passwork-credentials
key: token
- name: PASSWORK_MASTER_KEY
valueFrom:
secretKeyRef:
name: passwork-credentials
key: master-key
command:
- sh
- -c
- passwork-cli exec --folder-id "$SECRETS_FOLDER_ID" env > /secrets/.env
volumeMounts:
- name: secrets-volume
mountPath: /secrets

containers:
- name: app
image: order-service:latest
command:
- sh
- -c
- |
set -a && source /secrets/.env && set +a
exec ./app
volumeMounts:
- name: secrets-volume
mountPath: /secrets
readOnly: true

volumes:
- name: secrets-volume
emptyDir:
medium: Memory # in-memory only — not written to disk

The Kubernetes Secret passwork-credentials holds only the Passwork bootstrap tokens.

Sidecar pattern for periodic refresh

When secrets rotate frequently, a sidecar container refreshes the .env file without restarting the pod:

  containers:
- name: app
image: order-service:latest
# app reloads /secrets/.env when it detects a change (via inotify or polling)

- name: secrets-sync
image: passwork/passwork-cli:latest
env:
- name: PASSWORK_HOST
valueFrom:
secretKeyRef:
name: passwork-credentials
key: host
- name: PASSWORK_TOKEN
valueFrom:
secretKeyRef:
name: passwork-credentials
key: token
- name: PASSWORK_MASTER_KEY
valueFrom:
secretKeyRef:
name: passwork-credentials
key: master-key
command:
- sh
- -c
- |
while true; do
passwork-cli exec --folder-id "$SECRETS_FOLDER_ID" env > /secrets/.env.new
mv /secrets/.env.new /secrets/.env
sleep 300
done
volumeMounts:
- name: secrets-volume
mountPath: /secrets

Audit trail

Every secret access by a service account is recorded in Passwork's action history under the service account's identity. This gives you a complete, centralized audit trail:

  • Which pipeline fetched which credentials and when
  • Which rotation script updated which item
  • Any access outside expected patterns (alert candidates)

Navigate to Settings → Activity log and filter by the service account username to review its activity.

For full CI/CD integration reference, see CI/CD and infrastructure integrations.