Secrets Management¶
How to store and reference secrets for SOFS + FSLogix CI/CD pipelines.
Principles¶
- Never commit secrets —
config/variables.ymlis gitignored; usekeyvault://URIs for all sensitive values - Least privilege — service principals get only the roles they need (Key Vault Secrets User, Contributor on the resource group)
- Prefer OIDC / federated credentials over client secrets where supported
- Rotate regularly — Key Vault handles rotation; CI/CD platform secrets should be reviewed quarterly
Secret Categories¶
| Category | Examples | Where to Store |
|---|---|---|
| Azure identity | Client ID, Tenant ID, Subscription ID | CI/CD platform variables |
| Azure credentials | Client Secret or OIDC federation | CI/CD platform secrets (masked) |
| VM passwords | Local admin, domain join | Azure Key Vault only |
| Ansible vault | Vault password | CI/CD platform secret |
| Terraform state | Storage account key (if not using MSI) | CI/CD platform secret |
Platform Setup Guides¶
Detailed per-platform instructions:
- GitHub Secrets — Repo secrets, org secrets, OIDC setup
- GitLab Variables — Project/group variables, protected/masked flags
- Azure DevOps Variable Groups — Variable groups, service connections, Key Vault linking
Azure Key Vault Integration¶
For production, secrets like VM passwords and domain join credentials live in Key Vault:
# config/variables.yml
vm:
admin_password: "keyvault://kv-platform-prod/sofs-vm-admin-password"
domain:
join_password: "keyvault://kv-platform-prod/domain-join-password"
Each CI/CD platform can pull these at pipeline runtime. See Key Vault Integration for per-platform details.
OIDC / Workload Identity Federation (Recommended)¶
Instead of storing a client secret, configure federated credentials:
Azure AD App Registration
→ Certificates & secrets
→ Federated credentials
→ Add credential
→ GitHub Actions / GitLab CI / other
This eliminates secret rotation for the CI/CD identity itself.
GitHub Actions OIDC¶
permissions:
id-token: write
contents: read
steps:
- uses: azure/login@v2
with:
client-id: ${{ secrets.AZURE_CLIENT_ID }}
tenant-id: ${{ secrets.AZURE_TENANT_ID }}
subscription-id: ${{ secrets.AZURE_SUBSCRIPTION_ID }}
No AZURE_CLIENT_SECRET needed.
Complete Variables Reference¶
See Variables Reference for a full table of every secret and variable name, which tools use it, and where to store it.
Best Practices¶
- Mask secrets in logs — all platforms support this; GitLab and Azure DevOps do it automatically for masked/secret variables
- Use environment scoping — production secrets should only be available to production pipelines
- Audit access — Key Vault provides access logs; enable diagnostic settings to a Log Analytics workspace
- Separate Key Vaults per environment —
kv-platform-stagingvskv-platform-prod - Never echo secrets — use
::add-mask::(GitHub),[MaskOutput](GitLab), or avoidWrite-Hostfor secret values