Secrets Management in CI/CD

Why Secrets Management?

Never hardcode sensitive information like API keys, passwords, or tokens in code. Use secure secrets management instead.

GitHub Actions Secrets

name: Deploy

on: [push]

jobs:
  deploy:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v3
      
      - name: Deploy to AWS
        env:
          AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }}
          AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
          DATABASE_URL: ${{ secrets.DATABASE_URL }}
        run: ./deploy.sh

Environment-Specific Secrets

jobs:
  deploy-staging:
    environment: staging
    steps:
      - name: Deploy
        env:
          API_KEY: ${{ secrets.STAGING_API_KEY }}
          DB_PASSWORD: ${{ secrets.STAGING_DB_PASSWORD }}
        run: ./deploy.sh staging
  
  deploy-production:
    environment: production
    steps:
      - name: Deploy
        env:
          API_KEY: ${{ secrets.PROD_API_KEY }}
          DB_PASSWORD: ${{ secrets.PROD_DB_PASSWORD }}
        run: ./deploy.sh production

Kubernetes Secrets

# Create secret
apiVersion: v1
kind: Secret
metadata:
  name: app-secrets
type: Opaque
data:
  database-url: cG9zdGdyZXNxbDovL3Bvc3RncmVzOnBhc3N3b3JkQGxvY2FsaG9zdDo1NDMyL215YXBw
  api-key: YWJjMTIzNDU2Nzg5
  jwt-secret: c3VwZXJzZWNyZXRrZXk=

---
# Use in deployment
apiVersion: apps/v1
kind: Deployment
metadata:
  name: myapp
spec:
  template:
    spec:
      containers:
        - name: myapp
          env:
            - name: DATABASE_URL
              valueFrom:
                secretKeyRef:
                  name: app-secrets
                  key: database-url
            - name: API_KEY
              valueFrom:
                secretKeyRef:
                  name: app-secrets
                  key: api-key

HashiCorp Vault

// Node.js with Vault
const vault = require('node-vault')({
  endpoint: 'http://vault:8200',
  token: process.env.VAULT_TOKEN
});

async function getSecrets() {
  const dbSecret = await vault.read('secret/database');
  const apiSecret = await vault.read('secret/api');
  
  return {
    databaseUrl: dbSecret.data.url,
    apiKey: apiSecret.data.key
  };
}

// Use secrets
const secrets = await getSecrets();
const db = await connectDatabase(secrets.databaseUrl);

Azure Key Vault

// .NET with Azure Key Vault
using Azure.Identity;
using Azure.Security.KeyVault.Secrets;

var client = new SecretClient(
    new Uri("https://myvault.vault.azure.net/"),
    new DefaultAzureCredential()
);

var databaseUrl = await client.GetSecretAsync("DatabaseUrl");
var apiKey = await client.GetSecretAsync("ApiKey");

// Use secrets
var connectionString = databaseUrl.Value.Value;

AWS Secrets Manager

// Node.js with AWS Secrets Manager
const AWS = require('aws-sdk');
const secretsManager = new AWS.SecretsManager();

async function getSecret(secretName) {
  const data = await secretsManager.getSecretValue({
    SecretId: secretName
  }).promise();
  
  return JSON.parse(data.SecretString);
}

// Use secrets
const dbCreds = await getSecret('prod/database');
const apiKeys = await getSecret('prod/api-keys');

Docker Secrets

# docker-compose.yml
version: '3.8'

services:
  app:
    image: myapp:latest
    secrets:
      - db_password
      - api_key
    environment:
      - DB_PASSWORD_FILE=/run/secrets/db_password
      - API_KEY_FILE=/run/secrets/api_key

secrets:
  db_password:
    file: ./secrets/db_password.txt
  api_key:
    file: ./secrets/api_key.txt
// Read Docker secret
const fs = require('fs');

function readSecret(secretName) {
  const secretPath = `/run/secrets/${secretName}`;
  return fs.readFileSync(secretPath, 'utf8').trim();
}

const dbPassword = readSecret('db_password');
const apiKey = readSecret('api_key');

Environment Variables

# .env (NOT committed to git)
DATABASE_URL=postgresql://user:password@localhost:5432/mydb
API_KEY=abc123xyz789
JWT_SECRET=supersecretkey
// Load with dotenv
require('dotenv').config();

const config = {
  databaseUrl: process.env.DATABASE_URL,
  apiKey: process.env.API_KEY,
  jwtSecret: process.env.JWT_SECRET
};

Encryption

// Encrypt secrets
const crypto = require('crypto');

function encrypt(text, key) {
  const iv = crypto.randomBytes(16);
  const cipher = crypto.createCipheriv('aes-256-cbc', Buffer.from(key), iv);
  
  let encrypted = cipher.update(text);
  encrypted = Buffer.concat([encrypted, cipher.final()]);
  
  return iv.toString('hex') + ':' + encrypted.toString('hex');
}

function decrypt(text, key) {
  const parts = text.split(':');
  const iv = Buffer.from(parts[0], 'hex');
  const encrypted = Buffer.from(parts[1], 'hex');
  
  const decipher = crypto.createDecipheriv('aes-256-cbc', Buffer.from(key), iv);
  
  let decrypted = decipher.update(encrypted);
  decrypted = Buffer.concat([decrypted, decipher.final()]);
  
  return decrypted.toString();
}

Best Practices

  1. Never commit secrets: Use .gitignore
  2. Rotate regularly: Change secrets periodically
  3. Least privilege: Minimal access rights
  4. Encrypt at rest: Encrypted storage
  5. Audit access: Track who accesses secrets
  6. Use secret managers: Vault, AWS Secrets Manager
  7. Environment-specific: Different secrets per environment

.gitignore

# Secrets and credentials
.env
.env.local
.env.*.local
*.key
*.pem
secrets/
credentials/

# Configuration files with secrets
config/production.json
appsettings.Production.json

Interview Tips

  • Explain importance: Never hardcode secrets
  • Show tools: GitHub Secrets, Vault, AWS Secrets Manager
  • Demonstrate Kubernetes: Secret resources
  • Discuss encryption: Protect sensitive data
  • Mention best practices: Rotation, least privilege
  • Show .gitignore: Prevent commits

Summary

Secrets management protects sensitive information in CI/CD pipelines. Use GitHub Actions secrets, Kubernetes secrets, or dedicated tools like Vault and AWS Secrets Manager. Never commit secrets to version control. Encrypt secrets at rest. Rotate regularly. Implement least privilege access. Essential for secure DevOps practices.

Test Your Knowledge

Take a quick quiz to test your understanding of this topic.

Test Your Cicd Knowledge

Ready to put your skills to the test? Take our interactive Cicd quiz and get instant feedback on your answers.