이 제품은 선택한 Datadog 사이트에서 지원되지 않습니다. ().
이 페이지는 아직 한국어로 제공되지 않습니다. 번역 작업 중입니다.
현재 번역 프로젝트에 대한 질문이나 피드백이 있으신 경우 언제든지 연락주시기 바랍니다.

Metadata

Id: terraform-kubernetes-service-account-allows-access-secrets

Provider: Kubernetes

Platform: Terraform

Severity: Medium

Category: Secret Management

Learn More

Description

kubernetes_role and kubernetes_cluster_role, when bound, should not include the verbs get, list, watch, or * in rules that grant access to secrets.
The rule inspects kubernetes_role_binding and kubernetes_cluster_role_binding entries that bind these roles to a ServiceAccount and checks the role’s rule.verbs for any of the restricted verbs.
Both single rule objects and arrays of rule entries are evaluated.

Compliant Code Examples

# Cluster Role
resource "kubernetes_cluster_role" "negative_cluster_role" {
  metadata {
    name = "terraform-example-1"
  }

  rule {
    api_groups = [""]
    resources  = ["namespaces", "pods"]
    verbs      = ["get", "list", "watch"]
  }
}

resource "kubernetes_cluster_role_binding" "example" {
  metadata {
    name = "terraform-example-2"
  }
  role_ref {
    api_group = "rbac.authorization.k8s.io"
    kind      = "ClusterRole"
    name      = "terraform-example-1"
  }
  subject {
    kind      = "User"
    name      = "admin"
    api_group = "rbac.authorization.k8s.io"
  }
  subject {
    kind      = "ServiceAccount"
    name      = "default"
    namespace = "kube-system"
  }
  subject {
    kind      = "Group"
    name      = "system:masters"
    api_group = "rbac.authorization.k8s.io"
  }
}

# Role
resource "kubernetes_role" "negative_role" {
  metadata {
    name = "terraform-example"
    labels = {
      test = "MyRole"
    }
  }

  rule {
    api_groups     = [""]
    resources      = ["pods"]
    resource_names = ["foo"]
    verbs          = ["get", "list", "watch"]
  }
  rule {
    api_groups = ["apps"]
    resources  = ["deployments"]
    verbs      = ["get", "list"]
  }
}

resource "kubernetes_role_binding" "example" {
  metadata {
    name      = "terraform-example"
    namespace = "default"
  }
  role_ref {
    api_group = "rbac.authorization.k8s.io"
    kind      = "Role"
    name      = "terraform-example"
  }
  subject {
    kind      = "User"
    name      = "admin"
    api_group = "rbac.authorization.k8s.io"
  }
  subject {
    kind      = "ServiceAccount"
    name      = "default"
    namespace = "kube-system"
  }
  subject {
    kind      = "Group"
    name      = "system:masters"
    api_group = "rbac.authorization.k8s.io"
  }
}

# Role whose Terraform label happens to match a role_ref.name used elsewhere,
# but whose real metadata.name does not - must not be flagged (old code
# compared role_ref.name against the label, not metadata.name).
resource "kubernetes_role" "label_lookalike" {
  metadata {
    name = "actual-unbound-role"
  }

  rule {
    api_groups = [""]
    resources  = ["secrets"]
    verbs      = ["*"]
  }
}

resource "kubernetes_role_binding" "label_lookalike" {
  metadata {
    name      = "label-lookalike-binding"
    namespace = "default"
  }
  role_ref {
    api_group = "rbac.authorization.k8s.io"
    kind      = "Role"
    name      = "label_lookalike"
  }
  subject {
    kind      = "ServiceAccount"
    name      = "default"
    namespace = "kube-system"
  }
}

# Role whose real metadata.name matches a RoleBinding's role_ref.name, but the
# RoleBinding lives in a different namespace - RoleBindings only bind Roles in
# their own namespace, so this must not be flagged.
resource "kubernetes_role" "cross_namespace_role" {
  metadata {
    name      = "actual-role"
    namespace = "ns-a"
  }

  rule {
    api_groups = [""]
    resources  = ["secrets"]
    verbs      = ["*"]
  }
}

resource "kubernetes_role_binding" "cross_namespace_binding" {
  metadata {
    name      = "cross-namespace-binding"
    namespace = "ns-b"
  }
  role_ref {
    api_group = "rbac.authorization.k8s.io"
    kind      = "Role"
    name      = "actual-role"
  }
  subject {
    kind      = "ServiceAccount"
    name      = "default"
    namespace = "ns-b"
  }
}

Non-Compliant Code Examples

# Cluster Role
resource "kubernetes_cluster_role" "positive_cluster_role" {
  metadata {
    name = "terraform-example-1"
  }

  rule {
    api_groups = [""]
    resources  = ["namespaces", "pods", "secrets"]
    verbs      = ["get", "list", "watch"]
  }
}

resource "kubernetes_cluster_role_binding" "example" {
  metadata {
    name = "terraform-example-2"
  }
  role_ref {
    api_group = "rbac.authorization.k8s.io"
    kind      = "ClusterRole"
    name      = "terraform-example-1"
  }
  subject {
    kind      = "User"
    name      = "admin"
    api_group = "rbac.authorization.k8s.io"
  }
  subject {
    kind      = "ServiceAccount"
    name      = "default"
    namespace = "kube-system"
  }
  subject {
    kind      = "Group"
    name      = "system:masters"
    api_group = "rbac.authorization.k8s.io"
  }
}

# Role
resource "kubernetes_role" "positive_role" {
  metadata {
    name = "terraform-example"
    labels = {
      test = "MyRole"
    }
  }

  rule {
    api_groups     = [""]
    resources      = ["pods"]
    resource_names = ["foo"]
    verbs          = ["get", "list", "watch"]
  }
  rule {
    api_groups = ["apps"]
    resources  = ["deployments"]
    verbs      = ["get", "list"]
  }
   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      = "terraform-example"
  }
  subject {
    kind      = "User"
    name      = "admin"
    api_group = "rbac.authorization.k8s.io"
  }
  subject {
    kind      = "ServiceAccount"
    name      = "default"
    namespace = "kube-system"
  }
  subject {
    kind      = "Group"
    name      = "system:masters"
    api_group = "rbac.authorization.k8s.io"
  }
}
# ClusterRole bound to a ServiceAccount via a RoleBinding (not a ClusterRoleBinding).
# A Kubernetes RoleBinding can reference a ClusterRole in its role_ref, granting
# the ClusterRole's permissions scoped to the binding's namespace.
resource "kubernetes_cluster_role" "clusterrole_via_rolebinding" {
  metadata {
    name = "secret-reader"
  }

  rule {
    api_groups = [""]
    resources  = ["secrets"]
    verbs      = ["get", "list", "watch"]
  }
}

resource "kubernetes_role_binding" "clusterrole_via_rolebinding" {
  metadata {
    name      = "secret-reader-binding"
    namespace = "default"
  }
  role_ref {
    api_group = "rbac.authorization.k8s.io"
    kind      = "ClusterRole"
    name      = "secret-reader"
  }
  subject {
    kind      = "ServiceAccount"
    name      = "default"
    namespace = "default"
  }
}