Skip to content

no-project-secret-access-for-service-account

Grant service accounts Secret Manager access per secret, not on the project.

Why

A project-level Secret Manager accessor grant lets the workload read every secret in the project, so removing one secret's environment variable from the service does not remove its access.

Fix

Grant roles/secretmanager.secretAccessor with google_secret_manager_secret_iam_member on each secret the service account needs.

Examples

Before — flagged A static role expression still grants project-wide access
main.tf
resource "google_project_iam_member" "api" {
role = join("", ["roles/secret", "manager.secretAccessor"])
member = "serviceAccount:worker@example.com"
}
After — preferred A source string does not prove the resulting identity
main.tf
resource "google_project_iam_member" "api" {
role = join("", ["roles/secret", "manager.secretAccessor"])
member = replace("serviceAccount:eng@example.com", "serviceAccount:", "group:")
}
Before — flagged A service account can read every project secret
main.tf
resource "google_project_iam_member" "api" {
role = "roles/secretmanager.secretAccessor"
member = "serviceAccount:${google_service_account.api.email}"
}
After — preferred A service account reads only the secret it needs
main.tf
resource "google_secret_manager_secret_iam_member" "api" {
secret_id = google_secret_manager_secret.api_key.id
role = "roles/secretmanager.secretAccessor"
member = "serviceAccount:${google_service_account.api.email}"
}