Description
When a Role or ClusterRole grants get, list, watch or broader permissions on secrets and is bound to a ServiceAccount, pods using that account can read Secret values within the granted scope. Secrets often contain sensitive tokens, passwords and certificates.
Not every workload needs to read Secrets. Grant narrowly scoped access only to applications that need it and remove it from other ServiceAccounts.
Potential impact
- Passwords, tokens and keys within the permitted scope can be exposed.
- Stolen credentials can enable further compromise of other systems.
- More identities with Secret access make permission control and incident investigation harder.
Remediation
- Remove unnecessary read permissions on
secretsfrom Roles and ClusterRoles. - Where Secret access is needed, limit the ServiceAccount to required namespaces, resources and operations.
- Use a ServiceAccount with a clear purpose instead of the default account, and periodically review actual bindings and permissions.
Examples
The RoleBinding grants the Role in the default namespace to the default ServiceAccount in kube-system. That account must exist separately. Retain the after-example Pod-read permissions only if the workload actually needs them.
Before
hcl
resource "kubernetes_role" "role_name" {
metadata {
name = "terraform-example"
}
rule {
api_groups = [""]
resources = ["secrets"]
verbs = ["*"]
}
}
resource "kubernetes_role_binding" "example" {
metadata {
name = "terraform-example"
namespace = "default"
}
role_ref {
api_group = "rbac.authorization.k8s.io"
kind = "Role"
name = kubernetes_role.role_name.metadata[0].name
}
subject {
kind = "ServiceAccount"
name = "default"
namespace = "kube-system"
}
}
After
hcl
resource "kubernetes_role" "role_name" {
metadata {
name = "terraform-example"
}
rule {
api_groups = [""]
resources = ["pods"]
verbs = ["get", "list", "watch"]
}
}
resource "kubernetes_role_binding" "example" {
metadata {
name = "terraform-example"
namespace = "default"
}
role_ref {
api_group = "rbac.authorization.k8s.io"
kind = "Role"
name = kubernetes_role.role_name.metadata[0].name
}
subject {
kind = "ServiceAccount"
name = "default"
namespace = "kube-system"
}
}
Explanation:
- Before: A Role allowing all operations on Secrets is bound to the account.
- After: Secret permissions are removed and Pod-read permissions are bound instead.