firebase / firebase/firebase-tools
Support loose binding / aliasing for existing GCP Secrets in `defineSecret`
- Dominant language
- TypeScript
- Stars
- 4.5k
- Forks
- 1.3k
- Avg merge
- 1d 12h
- Merged PRs (30d)
- 84
Description
### Description
`defineSecret()` requires the GCP Secret Manager secret ID to match the parameter name exactly. This breaks down when secrets are managed externally (Terraform, for example) under different naming conventions. There's no way to map `DB_PASSWORD` in your function to `prod-global-database-password-v2` in Secret Manager without either duplicating the secret or hardcoding the secret name in application code.
I'd like an option to point `defineSecret()` at an existing secret by resource path.
### Key Use Case
A team manages a database credential via Terraform as `prod-global-database-password-v2`. The Firebase Function should only know about `DB_PASSWORD`. Currently, trying to bridge that gap via `.env`:
```env
DB_PASSWORD=projects/my-project/secrets/prod-global-database-password-v2
```
causes `firebase deploy` to fail with a 400:
```
spec.template.spec.containers[0].env: Secret environment variable overlaps non secret environment variable: DB_PASSWORD
```
Firebase CLI writes the `.env` value to `environmentVariables` and the `defineSecret` binding to `secretEnvironmentVariables`. Cloud Run rejects both on the same key.
### Proposed Solution
If a value in `.env` uses a `Secret:` prefix, Firebase CLI should write it to `secretEnvironmentVariables` instead of `environmentVariables`:
```env
# .env
DB_PASSWORD=Secret:projects/my-project/secrets/prod-global-database-password-v2
```
(Open to alternate syntax — `sm://` or `secretmanager://` may align better with GCP conventions.)
TypeScript side stays unchanged:
```typescript
const dbPassword = defineSecret("DB_PASSWORD");
export const myFunction = onRequest({ secrets: [dbPassword] }, (req, res) => {
const token = dbPassword.value();
res.send("Success");
});
```
### How it maps to Cloud Run
Firebase CLI strips the `Secret:` prefix and writes directly to Cloud Run's `secretKeyRef`:
```json
{
"name": "DB_PASSWORD",
"valueSource": {
"secretKeyRef": {
"secret": "prod-global-database-password-v2",
"version": "latest"
}
}
}
```
This avoids the collision entirely.
### Alternatives Considered
**In-code mapping:** Pass `secrets: ["prod-global-database-password-v2"]` and assign manually with `const DB_PASSWORD = process.env.prod_global_database_password_v2` (Cloud Run converts hyphens to underscores). This hardcodes infrastructure names in application code and drops the benefits of `defineSecret()` (type checks, configuration validation).
**Duplicate the secret:** Create a `DB_PASSWORD` secret in the Firebase project that mirrors the Terraform-managed one. Two secrets to keep in sync.
I'm happy to submit a PR if the maintainers are open to the `.env` prefix approach.
Contributor guide
Assessment
This issue has not been assessed yet.