Add native GitLab Secrets Manager support to GitLab Runner
What does this MR do?
Resolves gitlab#540909 (closed)
This MR implements native GitLab Secrets Manager support in GitLab Runner using OpenBao's inline authentication feature. Given OpenBao is a fork of Vault, we also decided to fully replace the Vault module with OpenBao so we can reuse the existing Vault client and just add the inline-auth support to it.
This is the first part of a two-phase implementation that will eventually replace the current "masquerading" approach where Rails converts gitlab_secrets_manager secrets to vault format.
Phase 1 (this MR): Add native gitlab_secrets_manager support to Runner
Phase 2 (future MR): Rails stops masquerading and sends native format
Implementation overview
Architecture
This implementation follows the same patterns as the existing Vault resolver:
helpers/secrets/resolvers/gitlab_secrets_manager/
├── resolver.go # Main resolver (follows vault resolver pattern)
└── resolver_test.go # Comprehensive resolver tests
helpers/gitlab_secrets_manager/service/
├── gitlab_secrets_manager.go # Service layer implementation
├── gitlab_secrets_manager_test.go # Service tests
└── mocks.go # Service mocks for testing
Key Design Decisions
1. OpenBao Inline Authentication
Why inline auth?
- Performance: No separate authentication step required
- Efficiency: Credentials sent with each request, avoiding token storage/refresh cycles
- CI/CD Optimized: Better suited for ephemeral CI/CD workloads
- Stateless: No need to manage authentication state between requests
How it works:
GET /v1/project_123/ci/data/database_password
X-Vault-Inline-Auth-Path: auth/gitlab_rails_jwt/login
X-Vault-Inline-Auth-Parameter-token: <base64-url-encoded-jwt>
X-Vault-Inline-Auth-Parameter-role: <base64-url-encoded-role>
2. No Variable Expansion
Unlike other secret resolvers, GitLab Secrets Manager deliberately does not expand variables.
Rationale:
- Only user input is the secret name from
.gitlab-ci.yml - All server URLs, auth paths, JWT tokens, and roles are generated internally by Rails
- This prevents users from tampering with authentication parameters
- Maintains security by keeping all sensitive configuration server-side
3. Reuse existing Vault Client
Decision: Replace HashiCorp Vault SDK with OpenBao SDK and extend the existing vault client rather than creating a new one.
Benefits:
- Code Reuse: Leverages battle-tested vault client code for connection management, error handling, and API interactions
- Minimal Changes: Only adds inline auth support to existing client - all other functionality remains unchanged
- Reduced Maintenance: Single client implementation to maintain instead of two separate ones
- API Compatibility: OpenBao maintains full API compatibility with Vault, making this a drop-in replacement
Configuration Format
User configuration (in .gitlab-ci.yml):
test_job:
secrets:
DATABASE_PASSWORD:
gitlab_secrets_manager:
name: database_credentials
What Rails sends to Runner (this MR supports this format):
{
"secrets": {
"DATABASE_PASSWORD": {
"gitlab_secrets_manager": {
"server": {
"url": "https://openbao.gitlab.com",
"namespace": <for future use, just in case>
"inline_auth": {
"path": "gitlab_rails_jwt",
"data": {
"jwt": "eyJ...",
"role": "project_123_ci"
}
}
},
"engine": {
"name": "kv-v2",
"path": "project_123/ci"
},
"path": "database_credentials",
"field": "value"
}
}
}
}
Backward Compatibility
- No breaking changes: Existing vault, AWS, GCP, and Azure secret resolvers unchanged
-
Additive feature: New resolver only activates for
gitlab_secrets_managersecrets - Rails compatibility: Supports the format Rails will send in the future