InfoGrab DocsInfoGrab Docs

Teleport Kubernetes 접근 제어

요약

이 가이드는 Teleport Kubernetes 서비스가 Teleport 사용자가 Kubernetes 클러스터와 상호 작용할 때 역할 기반 접근 제어를 적용하는 방법을 설명합니다. 이 가이드에서는 Teleport에 연결한 Kubernetes 클러스터에 대한 접근을 관리하기 위해 Teleport 역할 내에서 사용 가능한 필드를 구성하는 방법을 보여드립니다.

이 가이드는 Teleport Kubernetes 서비스가 Teleport 사용자가 Kubernetes 클러스터와 상호 작용할 때 역할 기반 접근 제어를 적용하는 방법을 설명합니다. Kubernetes 서비스는 Kubernetes API 서버에 대한 요청을 가로채고 사용자의 Teleport 역할에 따라 각 요청을 수정합니다.

이 가이드에서는 Teleport에 연결한 Kubernetes 클러스터에 대한 접근을 관리하기 위해 Teleport 역할 내에서 사용 가능한 필드를 구성하는 방법을 보여드립니다.

로컬 minikube 클러스터를 사용하여 Kubernetes로 Teleport 역할을 사용하는 방법의 예시는 RBAC 방법 가이드를 참조하세요.

Kubernetes 접근을 관리하는 역할 필드#

이 섹션에서는 Kubernetes 클러스터에 대한 접근을 구성하는 Teleport 역할 내 필드를 설명합니다.

Kubernetes 클러스터에 대한 접근을 관리하려면 Teleport 역할이 spec.allow 섹션에 다음 필드를 포함해야 합니다:

다음은 Kubernetes 클러스터에 대한 접근을 제한하는 Teleport 역할의 예시입니다:

kind: role
metadata:
  name: kube-access
version: v8
spec:
  allow:
    kubernetes_labels:
      region: '*'
      platform: minikube
    kubernetes_resources:
      - kind: pods
        namespace: production
        name: '^webapp-[a-z0-9-]+$'
        api_group: ''
      - kind: pods
        namespace: development
        name: '*'
        api_group: ''
      - kind: deployments
        namespace: development
        name: '*'
        api_group: apps
    kubernetes_groups:
    - developers
    kubernetes_users:
    - minikube
  deny: {}

kubernetes_labels#

Kubernetes 클러스터를 Teleport에 등록할 때 라벨을 추가할 수 있습니다. 역할의 kubernetes_labels 필드를 사용하여 서로 다른 라벨을 가진 Kubernetes 클러스터에 대한 사용자의 접근을 제한할 수 있습니다.

kind: role
metadata:
  name: kube-access
version: v8
spec:
  allow:
    kubernetes_labels:
      region: '*'
      environment: development
      # ...
  deny: {}

kubernetes_labels 필드의 값은 라벨 에서 하나 이상의 라벨 (즉, 문자열 또는 목록)으로의 매핑입니다.

Kubernetes 서비스가 kubernetes_labels를 평가하는 방식#

라벨의 키와 값이 모두 와일드카드, *인 경우, Teleport Kubernetes 서비스는 모든 라벨을 가진 Kubernetes 클러스터에 대한 접근을 사용자에게 허용합니다:

spec:
  allow:
    kubernetes_labels:
      '*': '*'
    # ...

그렇지 않은 경우, Kubernetes 서비스는 kubernetes_labels의 모든 키가 등록된 Kubernetes 클러스터에 해당하는 키와 일치하는지 확인합니다. 일치하지 않으면 일치하는 Kubernetes 클러스터가 없으므로 Kubernetes 서비스는 요청을 거부합니다.

예를 들어, environment 키는 포함하지만 region 키는 포함하지 않는 라벨을 가진 클러스터는 위의 kube-access 역할에서 kubernetes_labels 필드와 일치하지 않습니다.

그런 다음 Kubernetes 서비스는 kubernetes_labels의 키에 해당하는 Kubernetes 클러스터 라벨의 값을 가져옵니다. kubernetes_labels의 각 키 값은 Kubernetes 서비스가 사용자에게 클러스터 접근을 허용하기 전에 Kubernetes 클러스터 라벨의 값과 반드시 일치해야 합니다.

예를 들어, 위의 kube-access 역할은 region 키가 있고 어떤 값을 가지든 사용자가 Kubernetes 클러스터에 접근하도록 허용합니다. 이 역할은 사용자를 environment 키가 있고 development 값을 가진 Kubernetes 클러스터로 제한합니다. kubernetes_labels 내 키의 유효한 값에 대해서는 다음 섹션에서 설명합니다.

라벨 값#

kubernetes_labels의 라벨 키가 Kubernetes 클러스터의 키와 일치하려면 정확히 일치해야 합니다. 그러나 값의 경우, 유연성을 제공하기 위해 정규 표현식, 와일드카드, 여러 값을 구성할 수 있습니다.

정규 표현식과 와일드카드#

문자열의 부분 집합이나 변형을 일치시키기 위해 정규 표현식 또는 와일드카드 문자를 사용할 수 있습니다. 값이 ^로 시작하고 $로 끝나면, Kubernetes 서비스는 이를 Go의 re2 구문을 사용하는 정규 표현식으로 처리합니다(re2 README 참조).

그렇지 않으면 Kubernetes 서비스는 값 내에서 와일드카드를 평가하여 라벨의 임의 문자 시퀀스와 일치시킵니다.

다음은 예시입니다:

spec:
  allow:
    kubernetes_labels:
      region: 'us-east-*'
      team: '^data-eng-[a-z-]+$'
    # ...

allow 규칙은 region:us-east-1region:us-east-2b 라벨을 가진 클러스터와 일치합니다. 또한 team:data-eng-analyticsteam:data-eng-ml-training 라벨을 가진 클러스터와도 일치합니다.

여러 값#

kubernetes_labels의 키에 여러 값이 있는 경우, Kubernetes 서비스는 이러한 값 중 어느 하나라도 Kubernetes 클러스터의 라벨과 일치하면 라벨 값이 일치하는 것으로 간주합니다. 예를 들어, 다음 kubernetes_labels 구성은 region:us-east-2 라벨과 development 또는 staging 환경 중 하나를 가진 클러스터와 일치합니다:

spec:
  allow:
    kubernetes_labels:
      region: 'us-east-*'
      environment: ['development', 'staging']
    # ...

라벨 적용#

Teleport Kubernetes 서비스 인스턴스에 라벨을 적용할 수 있습니다. 그 방법은 서비스를 실행한 방식에 따라 다릅니다:

teleport-kube-agent Helm 차트를 설치하거나 업그레이드할 때 라벨을 설정합니다. 예시:

$ helm upgrade teleport-agent teleport/teleport-kube-agent --set kubeClusterName=${CLUSTER?}\
  --set proxyAddr=${PROXY?} --set authToken=${TOKEN?} --create-namespace --namespace=teleport-agent\
  --set labels.env=prod --set labels.region=us-west-1

teleport 인스턴스의 구성 파일에서 Teleport Kubernetes 서비스를 활성화할 때 라벨을 설정합니다:

kubernetes_service:
  enabled: true
  kube_cluster_name: cookie
  labels:
    env: prod
    region: us-west-1

kubernetes_groupskubernetes_users#

Teleport Kubernetes 서비스는 예를 들어 kubectl을 통해 최종 사용자로부터 요청을 받아 Kubernetes API 서버로 전달합니다. Kubernetes 서비스는 임퍼소네이션 헤더를 사용하여 하나의 Kubernetes 사용자와 0개 이상의 Kubernetes 그룹으로 API 서버에 요청을 전송합니다.

Impersonation

kubernetes_userskubernetes_groups 필드는 사용자가 Kubernetes API 서버에 요청을 보낼 때 어떤 사용자와 그룹을 사용자가 가정하도록 허용할지 나타냅니다:

kind: role
metadata:
  name: kube-access
version: v7
spec:
  allow:
    kubernetes_groups:
    - developers
    - viewers
    kubernetes_users:
    - myuser
    - system:serviceaccount:someNamespace:saName # 서비스 계정 이름
    # ...
  deny: {}

kubernetes_groupskubernetes_users의 값은 임퍼소네이션을 활성화할 그룹, 사용자, 또는 서비스 계정의 이름 목록입니다.

Kubernetes 사용자와 그룹#

Kubernetes 사용자와 그룹은 Kubernetes 클러스터에 존재하는 엔티티이며, ClusterRoleBinding 또는 RoleBinding 리소스를 통해 권한이 제어됩니다. 클러스터에 존재하지 않는 경우, Kubernetes RBAC은 이를 무시합니다.

다음은 내장된 view ClusterRolecluster-viewer-group 그룹과 cluster-viewer-user 사용자에게 할당하는 ClusterRoleBinding 리소스의 예시입니다:

apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
  name: cluster-viewer
roleRef:
  apiGroup: rbac.authorization.k8s.io
  kind: ClusterRole
  name: view
subjects:
- apiGroup: rbac.authorization.k8s.io
  kind: Group
  name: cluster-viewer-group
- apiGroup: rbac.authorization.k8s.io
  kind: User
  name: cluster-viewer-user

이 시점에서 사용자와 그룹은 Kubernetes 네임스페이스의 리소스를 볼 수 있는 동일한 권한을 갖습니다. Kubernetes는 요청에 사용된 임퍼소네이션 프린시펄과 관련된 권한을 병합하기 때문에, Kubernetes 사용자와 그룹에 동일한 권한을 할당하는 것이 필수는 아닙니다.

Kubernetes 서비스 계정#

Teleport는 kubernetes_users 필드에 서비스 계정의 정규화된 이름을 사용하여 서비스 계정 임퍼소네이션을 지원합니다.

서비스 계정의 정규화된 이름은 다음 패턴으로 구성됩니다:

system:serviceaccount:<namespace>:<service_account_name>

FQN은 system:serviceaccount:로 시작해야 합니다. 그렇지 않으면 Kubernetes는 이를 일반 사용자로 평가합니다.

서비스 계정을 임퍼소네이트하는 역할의 예시는 다음과 같습니다.

kind: role
metadata:
  name: kube-access-impersonate-sa
version: v7
spec:
  allow:
    kubernetes_users:
    - system:serviceaccount:someNamespace:saName
    # ...
  deny: {}

Teleport 사용자가 Kubernetes 사용자, 그룹, 서비스 계정을 임퍼소네이트하는 방법#

최종 사용자가 임퍼소네이트할 사용자 또는 서비스 계정과 그룹을 지정하는 방법에는 두 가지가 있습니다:

수동으로#

사용자가 Kubernetes 클러스터에 인증하기 위해 tsh kube login을 실행할 때, --as--as-groups 플래그를 사용하여 인증할 사용자와 그룹을 수동으로 지정할 수 있습니다. Teleport Kubernetes 서비스는 해당 사용자와 그룹이 사용자의 kubernetes_userskubernetes_groups 구성에 속하는지 확인하고, 그렇지 않은 경우 사용자의 접근을 거부합니다.

자동으로#

클러스터에 인증할 때 사용자가 Kubernetes 사용자와 Kubernetes 그룹을 명시적으로 지정하지 않은 경우, Teleport Kubernetes 서비스는 사용자 역할의 kubernetes_userskubernetes_groups 필드로부터 이를 결정합니다.

사용자가 kubernetes_users에 정확히 하나의 값을 가지고 있으면, Teleport Kubernetes 서비스는 해당 사용자를 임퍼소네이트합니다. kubernetes_users에 값이 없거나 와일드카드(*)가 있으면, Kubernetes 서비스는 사용자의 Teleport 사용자 이름을 사용합니다.

사용자가 여러 개의 kubernetes_users를 가지고 있고 클러스터에 인증할 때 하나를 지정하지 않은 경우(즉, 이전 섹션에서 설명한 --as 플래그를 사용하지 않은 경우), Kubernetes 서비스는 요청을 거부합니다.

사용자가 임퍼소네이트할 Kubernetes 그룹을 지정하지 않은 경우, Kubernetes 서비스는 kubernetes_groups 내의 모든 값을 사용합니다.

Warning

권한이 낮은 사용자를 임퍼소네이트할 때, 특정 그룹을 수동으로 임퍼소네이트하지 않는 한 (예: --as-groups 플래그 사용), Kubernetes 서비스는 kubernetes_groups 내의 모든 그룹을 자동으로 임퍼소네이트한다는 점을 기억하세요.

이는 사용자와 자동으로 임퍼소네이트된 그룹 모두의 결합된 권한을 갖게 되므로 혼란을
일으킬 수 있습니다.

위의 kube-access 역할을 사용하면, Teleport에 인증한 후 Kubernetes 서비스는 임퍼소네이션 헤더를 사용하여 developers 그룹과 myuser Kubernetes 사용자로 요청을 API 서버에 전달합니다.

임퍼소네이션 활성화#

Kubernetes 서비스가 임퍼소네이션 헤더로 사용자 요청을 전달하도록 활성화하려면, 서비스 계정이 클러스터 내에서 Kubernetes RBAC 프린시펄을 임퍼소네이트할 권한을 갖도록 해야 합니다. Kubernetes 서비스는 사용자가 접근 권한이 없는 사용자 또는 그룹을 임퍼소네이트하려는 요청을 거부합니다.

아래는 임퍼소네이션을 활성화하는 데 필요한 최소 권한 집합을 부여하는 Kubernetes ClusterRole과, 이러한 권한을 서비스 계정에 부여하는 ClusterRoleBinding입니다.

Tip

일반적으로 이러한 리소스를 수동으로 정의할 필요는 없습니다. Kubernetes 클러스터를 Teleport에 등록하는 수동 방법자동 방법에는 Teleport가 클러스터 접근을 허용하기 위해 필요한 Kubernetes RBAC 리소스를 설정하는 단계가 포함되어 있습니다.

apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
  name: teleport-impersonation
rules:
- apiGroups:
  - ""
  resources:
  - users
  - groups
  - serviceaccounts
  verbs:
  - impersonate
- apiGroups:
  - ""
  resources:
  - pods
  verbs:
  - get
- apiGroups:
  - "authorization.k8s.io"
  resources:
  - selfsubjectaccessreviews
  verbs:
  - create
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
  name: teleport
roleRef:
  apiGroup: rbac.authorization.k8s.io
  kind: ClusterRole
  name: teleport-impersonation
subjects:
- kind: ServiceAccount
  name: teleport-serviceaccount
  namespace: default

사용자 트레이트를 기반으로 그룹과 사용자 지정#

Teleport 역할에 이 정보를 하드코딩하는 대신, 각 Teleport 사용자별로 개별적으로 Kubernetes 그룹과 사용자를 지정할 수 있습니다. 이를 위해 Teleport 역할에 템플릿 변수를 추가할 수 있으며, Teleport Auth 서비스가 인증하는 각 사용자의 정보로 이를 채웁니다.

Teleport 역할에서 템플릿 변수 확장이 작동하는 방식에 대한 자세한 내용은 Access Controls Reference를 참조하세요.

싱글 사인온 제공업체 트레이트#

Teleport의 역할은 템플릿 변수를 사용하여 OIDC 클레임 또는 SAML 속성을 매핑합니다. Teleport Auth 서비스는 {{external.*}} 형식의 템플릿 변수를 해당하는 SAML 속성 또는 OIDC 클레임으로 대체합니다:

kind: role
version: v7
metadata:
  name: group-member
spec:
  allow:
    kubernetes_groups: ["{{external.groups}}"]
    kubernetes_users: ["{{external.kube_username}}"]
    # ...

예를 들어, 사용자가 SAML 커넥터를 통해 Teleport에 인증하고, 해당 사용자가 값이 myuserkube_username 속성과 값이 developersviewersgroups 속성을 가지고 있는 경우, 위의 group-member 역할은 다음과 같이 평가됩니다:

kind: role
version: v7
metadata:
  name: group-member
spec:
  allow:
    kubernetes_groups: ["developers", "viewers"]
    kubernetes_users: ["myuser"]
    # ...
로컬 사용자 트레이트#

로컬 사용자의 경우, user 리소스의 spec.traits 필드에 임의의 키-값 데이터를 지정한 다음, 역할에서 {{external.*}} 템플릿 변수를 사용하여 해당 트레이트를 참조할 수 있습니다.

예를 들어, 다음 역할은 내부 트레이트로 kubernetes_userskubernetes_groups를 채웁니다:

kind: role
version: v7
metadata:
  name: group-member
spec:
  allow:
    kubernetes_groups: ["{{external.groups}}"]
    kubernetes_users: ["{{external.kube_username}}"]
    # ...

그런 다음 로컬 사용자를 생성하거나 수정할 때 이러한 템플릿 변수에 대한 값을 제공할 수 있습니다. 예를 들어, 다음 사용자 정의에는 Auth 서비스가 위의 역할 정의를 채우는 데 사용할 트레이트가 포함되어 있습니다:

kind: user
version: v2
metadata:
  name: alice
spec:
  roles:
    - group-member
  traits:
    groups:
      - developers
      - viewers
    kube_username:
      - myuser

적시 접근(just-in-time access) 구성#

특정 Kubernetes 리소스에 대한 적시 접근을 활성화하기 위해 Teleport 역할을 설정하는 경우, Teleport가 접근을 제한할 수 있는 Kubernetes 리소스 외에는 Kubernetes 리소스에 대한 접근 권한이 없는 프린시펄로 역할의 kubernetes_groupskubernetes_users를 설정해야 합니다.

이는 사용자가 Kubernetes 파드에 대한 접근을 요청하고 요청이 승인되면, Teleport Kubernetes 서비스가 역할의 kubernetes_groupskubernetes_users 필드를 사용하여 Kubernetes API 서버에 대한 사용자 요청에 임퍼소네이션 헤더를 추가하기 때문입니다. 이러한 조건에서 Teleport는 원하는 pod를 제외한 지원되는 모든 Kubernetes 리소스 종류에 대한 접근을 제한할 수 있습니다.

Teleport는 네임스페이스 범위의 커스텀 리소스에 대한 접근도 제한할 수 있지만, 클러스터 범위의 커스텀 리소스는 제한할 수 없습니다. 클러스터 범위인 CRD 리소스는 kubernetes_userskubernetes_groups 필드의 프린시펄이 접근 권한을 가지고 있으면 사용자에게 접근 가능합니다.

Kubernetes 네임스페이스에 대한 접근을 요청하면 해당 네임스페이스의 모든 리소스에 접근할 수 있지만, 클러스터의 다른 지원되는 리소스에는 접근할 수 없습니다.

kubernetes_resources#

kubernetes_resources 필드는 Teleport 역할이 Kubernetes 클러스터의 특정 리소스에 대한 접근을 구성할 수 있도록 합니다.

이 필드의 값은 매핑 목록이며, 각 매핑은 다음과 같이 설명됩니다:

역할 V8#

Warning

역할 V8은 커스텀 리소스 정의(CRD)를 포함하여 모든 Kubernetes 리소스 종류에 대한 접근 관리를 지원합니다. 이를 위해 이전 역할 버전에 비해 kubernetes_resources 섹션이 처리되는 방식에 여러 변경 사항이 있습니다:

  • kind 필드는 항상 리소스 종류의 복수 형태를 지정해야 합니다
  • 핵심 API 그룹에 속하지 않는 리소스에는 api_group 필드를 설정해야 합니다
  • kind: namespaces는 이제 네임스페이스 리소스와 일치하며, 네임스페이스 내의 리소스와는 더 이상 일치하지 않습니다
  • namespace 필드가 설정되고 값이 * 이외인 경우 클러스터 범위 리소스와 일치하지 않습니다

이 동작은 이전 역할 버전과 다르므로, 이전 버전에서 V8로 역할을 마이그레이션하는 경우 kubernetes_resources 섹션을 조정해야 할 가능성이 높습니다.

kind: role
metadata:
  name: kube-access
version: v8
spec:
  allow:
    kubernetes_labels:
      "*": "*"
    kubernetes_resources:
      - kind: pods
        api_group: ""
        namespace: production
        name: webapp
        verbs: ["*"]
      - kind: deployments
        api_group: apps
        namespace: development
        name: "*"
    # ...
  • kind: 접근을 활성화할 리소스의 종류입니다. * 또는 종류의 복수 형태(예: pods, deployments, cronjobs, mycustomresources)일 수 있습니다. 리소스에 그룹이 있는 경우 api_group 필드에 지정해야 합니다. 예를 들어, pods는 그룹이 필요하지 않지만 deploymentsapi_group 필드를 apps로 설정해야 합니다.
    Tip

다음 명령을 실행하여 사용 가능한 리소스의 전체 목록과 해당 API 그룹을 확인할 수 있습니다:

$ kubectl api-resources --namespaced=true -o=name
$ kubectl api-resources --namespaced=false -o=name
  • 해당 줄에 .이 있으면, 종류는 . 앞의 첫 번째 요소이고 API 그룹은 첫 번째 . 이후의 모든 부분입니다.
  • 해당 줄에 .이 없으면, 종류는 전체 요소이며 API 그룹은 없습니다.
Warning
  • namespaces 종류는 네임스페이스에 속한 모든 리소스를 포함하지 않으며, 네임스페이스 자체만을 다룹니다. 이는 이전 역할 버전에서 리소스 자체와 네임스페이스 내의 모든 것을 다루었던 것과 다른 동작이므로, 기존 역할을 V8로 마이그레이션하는 경우 kubernetes_resources 섹션을 조정해야 할 가능성이 높습니다.
    • *를 포함한 종류는 이제 namespace 필드를 강제합니다. 클러스터 범위 리소스와 일치시키려면 namespace 필드가 비어 있거나 *여야 합니다. 이는 이전 역할 버전에서 namespace 필드와 관계없이 클러스터 범위 리소스를 포함했던 것과 다른 동작입니다.

와일드카드 *를 사용하면 클러스터 범위 리소스를 포함하여(종류/api_group 기준) 모든 리소스와 일치한다는 점에 유의하세요. 빈 문자열 ""을 사용하면 클러스터 범위 리소스와만 일치합니다. ^.+$와 같은 다른 값은 네임스페이스가 지정된 리소스와만 일치하고 클러스터 범위 리소스는 제외합니다.

namespace, name, api_group 필드에는 와일드카드 문자(*)를 추가하여 임의의 문자 시퀀스를 대체할 수 있습니다. 예를 들어, name: "pod-*-*"pod-1-apod-2-c라는 이름의 파드와 일치합니다. kubernetes_labels와 마찬가지로, 값이 ^로 시작하고 $로 끝나면 Kubernetes 서비스는 이를 Go의 re2 구문을 사용하는 정규 표현식으로 처리합니다 (re2 README 참조).

Tip

역할의 kubernetes_resources 필드에 이름이 지정된 파드에 사용자가 접근하려면, 사용자는 kubernetes_groups 또는 kubernetes_users 내에 적어도 하나의 값을 포함하는 Teleport 역할이 할당되어 있어야 합니다. Teleport는 접근을 허용하거나 거부하기 위해 Kubernetes 역할을 변경하지 않습니다. Kubernetes 서비스가 클러스터 내 파드에 대한 접근을 허용하거나 거부하기 위해 Teleport 역할을 평가하는 방식에 대한 설명은 다음 섹션을 참조하세요.

역할 V7#

Tip

역할 V7은 더 많은 kind 값에 대한 지원을 추가했습니다. 단수 이름을 사용하며, 이후 역할 버전에서는 복수 형태를 사용합니다.

Warning

와일드카드(*)와 namespace 종류는 특별한 의미를 가지므로, 이를 사용할 때는 의도와 이후 버전과의 동작 차이에 특별히 주의해야 합니다.

kind: role
metadata:
  name: kube-access
version: v7
spec:
  allow:
    kubernetes_labels:
      "*": "*"
    kubernetes_resources:
      - kind: pod
        namespace: production
        name: webapp
        verbs: ["*"]
    # ...

* 종류의 동작은 이후 버전과 약간 다릅니다. V7에서는 namespace 필드와 관계없이 클러스터 범위 리소스를 포함한 모든 리소스에 대한 접근을 허용합니다. 이후 역할 버전에서는 namespace 필드가 강제되므로, 업그레이드할 때 특히 deny 쪽에서 리소스를 조정해야 할 수 있습니다.

Warning

namespace 종류는 namespace 리소스 자체는 물론 그 안의 모든 리소스도 다룹니다. 이는 이후 역할 버전에서 리소스 자체만 다루는 것과 다른 동작이므로, 업그레이드할 때 특히 deny 쪽에서 리소스를 조정해야 할 수 있습니다.

Kind 부여하는 접근 권한
* namespace 필드와 관계없이 클러스터 범위 리소스를 포함한 모든 리소스
pod 파드
secret 시크릿
configmap ConfigMap
namespace 네임스페이스 및 그 안의 모든 리소스
service 서비스
serviceaccount 서비스 계정
kube_node 노드
persistentvolume PersistentVolume
persistentvolumeclaim PersistentVolumeClaim
deployment 디플로이먼트
replicaset ReplicaSet
statefulset StatefulSet
daemonset DaemonSet
clusterrole ClusterRole
kube_role Role
clusterrolebinding ClusterRoleBinding
rolebinding RoleBinding
cronjob CronJob
job Job
certificatesigningrequest CertificateSigningRequest
ingress Ingress

namespacename 필드 모두에 와일드카드 문자(*)를 추가하여 임의의 문자 시퀀스를 대체할 수 있습니다. 예를 들어, name: "pod-*-*"pod-1-apod-2-c라는 이름의 파드와 일치합니다. kubernetes_labels와 마찬가지로, 값이 ^로 시작하고 $로 끝나면 Kubernetes 서비스는 이를 Go의 re2 구문을 사용하는 정규 표현식으로 처리합니다(re2 README 참조).

Tip

역할의 kubernetes_resources 필드에 이름이 지정된 파드에 사용자가 접근하려면, 사용자는 kubernetes_groups 또는 kubernetes_users 내에 적어도 하나의 값을 포함하는 Teleport 역할이 할당되어 있어야 합니다. Teleport는 접근을 허용하거나 거부하기 위해 Kubernetes 역할을 변경하지 않습니다. Kubernetes 서비스가 클러스터 내 파드에 대한 접근을 허용하거나 거부하기 위해 Teleport 역할을 평가하는 방식에 대한 설명은 다음 섹션을 참조하세요.

역할 V6#

Tip

역할 V6은 kubernetes_resources 필드에 대한 지원을 도입했지만, 종류가 'pod'인 파드에 대한 접근만 허용하도록 제한되었습니다. 이후 역할 버전에서 추가 리소스에 대한 지원이 확장되었습니다.

kind: role
metadata:
  name: kube-access
version: v6
spec:
  allow:
    kubernetes_labels:
      "*": "*"
    kubernetes_resources:
      - kind: pod
        namespace: production
        name: webapp
    # ...

namespacename 필드 모두에 와일드카드 문자(*)를 추가하여 임의의 문자 시퀀스를 대체할 수 있습니다. 예를 들어, name: "pod-*-*"pod-1-apod-2-c라는 이름의 파드와 일치합니다. kubernetes_labels와 마찬가지로, 값이 ^로 시작하고 $로 끝나면 Kubernetes 서비스는 이를 Go의 re2 구문을 사용하는 정규 표현식으로 처리합니다(re2 README 참조).

Tip

역할의 kubernetes_resources 필드에 이름이 지정된 파드에 사용자가 접근하려면, 사용자는 kubernetes_groups 또는 kubernetes_users 내에 적어도 하나의 값을 포함하는 Teleport 역할이 할당되어 있어야 합니다. Teleport는 접근을 허용하거나 거부하기 위해 Kubernetes 역할을 변경하지 않습니다. Kubernetes 서비스가 클러스터 내 파드에 대한 접근을 허용하거나 거부하기 위해 Teleport 역할을 평가하는 방식에 대한 설명은 다음 섹션을 참조하세요.

예시#

production을 제외한 네임스페이스가 지정된 리소스에 대한 전체 접근#

다음 역할은 production 네임스페이스를 제외한 모든 네임스페이스의 모든 네임스페이스가 지정된 리소스에 대한 전체 접근을 부여하며, production에서는 어떤 리소스에도 접근할 수 없습니다.

kind: role
metadata:
  name: kube-access
version: v7
spec:
  allow:
    kubernetes_labels:
      "*": "*"
    kubernetes_resources:
      # v7에서 namespace는 네임스페이스 내의 모든 것을 의미합니다.
      - kind: namespace  # v7은 단수형을 사용합니다.
        name: "*"
        verbs: ["*"]
  deny:
    kubernetes_resources:
      - kind: namespace  # v7은 단수형을 사용합니다.
        name: production
        verbs: ["*"]
    # ...
kind: role
metadata:
  name: kube-access
version: v8
spec:
  allow:
    kubernetes_labels:
      "*": "*"
    kubernetes_resources:
      # 모든 네임스페이스에서 네임스페이스가 지정된 리소스에 대한 접근을 부여합니다.
      - kind: "*"
        api_group: "*"
        name: "*"
        namespace: "^.+$"  # 네임스페이스가 지정된 모든 리소스와 일치하며, 클러스터 범위 리소스는 일치하지 않습니다.
        verbs: ["*"]
      # 네임스페이스 리소스 자체에 대한 접근을 부여합니다.
      - kind: namespaces  # v8에서 namespaces는 네임스페이스 자체를 의미합니다. 클러스터 범위 리소스로 간주되므로 별도로 추가해야 합니다.
        name: "*"
        verbs: ["*"]
  deny:
    kubernetes_resources:
      # production 네임스페이스의 네임스페이스가 지정된 리소스에 대한 접근을 거부합니다.
      - kind: "*"
        api_group: "*"
        name: "*"
        namespace: production
        verbs: ["*"]
      # 네임스페이스 리소스 자체에 대한 접근을 거부합니다.
      - kind: namespaces  # v8은 복수형을 사용합니다.
        name: production
        verbs: ["*"]
    # ...

또는 다음과 같이 사용할 수도 있습니다:

kind: role
metadata:
  name: kube-access
version: v8
spec:
  allow:
    kubernetes_labels:
      "*": "*"
    kubernetes_resources:
      # 모든 항목에 대한 전체 접근을 부여합니다.
      - kind: "*"
        api_group: "*"
        name: "*"
        namespace: "*"  # v8에서 '*'는 네임스페이스가 지정된 리소스와 클러스터 범위 리소스 모두와 일치합니다.
        verbs: ["*"]
  deny:
    kubernetes_resources:
      # 클러스터 범위 리소스에 대한 접근을 거부합니다.
      - kind: "*"
        api_group: "*"
        name: "*"
        namespace: ""  # 빈 네임스페이스는 클러스터 범위 리소스만 일치함을 의미합니다.
        verbs: ["*"]
      # production 네임스페이스의 네임스페이스가 지정된 리소스에 대한 접근을 거부합니다.
      - kind: "*"
        api_group: "*"
        name: "*"
        namespace: production
        verbs: ["*"]
      # 네임스페이스 리소스 자체에 대한 접근을 거부합니다.
      - kind: namespaces  # v8은 복수형을 사용합니다.
        name: production
        verbs: ["*"]
    # ...
dev 네임스페이스와 clusterroles를 제외한 모든 클러스터 범위 리소스에 대한 전체 접근#

다음 역할은 dev 네임스페이스의 모든 리소스와 clusterroles를 제외한 모든 클러스터 범위 리소스에 대한 접근을 부여합니다.

kind: role
metadata:
  name: kube-access
version: v7
spec:
  allow:
    kubernetes_labels:
      "*": "*"
    kubernetes_resources:
      # v7에서 "*"는 네임스페이스와 관계없이 클러스터 범위 리소스를 포함합니다.
      - kind: "*"
        name: "*"
        namespace: dev
        verbs: ["*"]
  deny:
    kubernetes_resources:
      - kind: clusterrole  # v7은 단수형을 사용합니다.
        name: "*"
        verbs: ["*"]
    # ...
kind: role
metadata:
  name: kube-access
version: v8
spec:
  allow:
    kubernetes_labels:
      "*": "*"
    kubernetes_resources:
      # dev 네임스페이스의 모든 리소스에 대한 접근을 부여합니다.
      # v8에서는 네임스페이스가 설정된 경우 "*"에 클러스터 범위 리소스가 포함되지 않습니다.
      - kind: "*"
        api_group: "*"
        name: "*"
        namespace: dev
        verbs: ["*"]
      # 모든 클러스터 범위 리소스에 대한 접근을 부여합니다.
      - kind: "*"
        api_group: "*"
        name: "*"
        namespace: ""  # 빈 네임스페이스는 클러스터 범위 리소스만 일치함을 의미합니다.
        verbs: ["*"]
  deny:
    kubernetes_resources:
      - kind: clusterroles  # v8은 복수형을 사용합니다.
        api_group: "*"
        name: "*"
    # ...
모든 항목에 대한 전체 접근#
kind: role
metadata:
  name: kube-access
version: v7
spec:
  allow:
    kubernetes_labels:
      "*": "*"
    kubernetes_resources:
      - kind: "*"
        name: "*"
        namespace: "*"
        verbs: ["*"]
    # ...
kind: role
metadata:
  name: kube-access
version: v8
spec:
  allow:
    kubernetes_labels:
      "*": "*"
    kubernetes_resources:
      - kind: "*"
        api_group: "*"
        name: "*"
        namespace: "*"  # 와일드카드 '*'는 네임스페이스가 지정된 리소스와 클러스터 범위 리소스 모두와 일치합니다.
        verbs: ["*"]
    # ...

Kubernetes 서비스가 Teleport 역할을 평가하는 방식#

Teleport 사용자가 Kubernetes 클러스터의 API 서버에 요청을 보내면, Teleport Kubernetes 서비스는 요청을 가로채고 사용자의 인가를 검사합니다. 사용자가 특정 리소스를 볼 권한이 없는 경우 Kubernetes 서비스는 요청을 거부합니다. 사용자가 요청을 수행할 권한이 있는 경우, Kubernetes 서비스는 요청을 수정하여 적절한 API 서버로 전달합니다.

사용자 요청 인가#

Teleport Kubernetes 서비스는 요청을 받으면 사용자 역할 내의 두 필드를 평가합니다. 이러한 필드 중 하나라도 사용자가 요청을 수행하도록 허용하지 않으면, Kubernetes 서비스는 사용자에게 오류를 반환합니다:

kubernetes_labels#

Teleport Kubernetes 서비스는 파드가 실행 중인 클러스터에 사용자의 kubernetes_labels 구성과 일치하는 라벨이 있는 경우에만 파드에 대한 접근을 허용합니다.

kubernetes_resources#

Kubernetes API 서버 내의 일부 리소스 URI에는 특정 리소스의 이름이 포함됩니다.

예를 들어, 사용자가 kubectl exec를 실행하여 development 네임스페이스의 webapp 파드에 대해 명령을 실행하면, kubectl은 대상 클러스터의 API 서버에 다음 경로로 요청을 보냅니다:

"/api/v1/namespaces/development/pods/webapp/exec"

Kubernetes API 서버에 대한 요청의 URL 경로 내에 Kubernetes 파드가 있는 경우, Teleport Kubernetes 서비스는 사용자가 해당 파드에 접근할 권한이 있는지 확인합니다.

위 예시에서 Kubernetes 서비스는 사용자가 development 네임스페이스의 webapp 파드에 접근할 권한이 있는지 확인하고, 없으면 요청을 거부합니다.

사용자 요청 전달#

Teleport Kubernetes 서비스가 사용자가 Kubernetes 클러스터와 (해당하는 경우) 특정 리소스에 대해 요청을 수행할 권한이 있다고 인가하면, 상위 API 서버에 대한 요청을 조립합니다. 사용자 역할의 kubernetes_groupskubernetes_users 필드(앞서 설명한 이 필드에 대한 설명 참조)를 기반으로 요청에 임퍼소네이션 헤더를 추가합니다.

Teleport Kubernetes 서비스는 Teleport 사용자의 kubernetes_groupskubernetes_users 필드에 나열된 RBAC 프린시펄을 통해 상위 API 서버에 접근하므로, 이러한 필드에 지정하는 프린시펄은 사용자의 kubernetes_resources 필드에 나열된 리소스에 대한 접근 권한을 가지고 있어야 합니다. 그렇지 않으면 Kubernetes 서비스는 부적절한 인가로 요청을 상위 API 서버에 전달하게 되고, API 서버는 요청을 거부합니다.

여러 역할#

Kubernetes 서비스가 여러 역할을 평가하는 방식#

Teleport Kubernetes 서비스는 사용자의 Kubernetes API 서버에 대한 요청을 평가하기 전에 사용자의 각 역할을 확인합니다. 한 역할의 spec.allow.kubernetes_labels 또는 spec.allow.kubernetes_resources 조건이 사용자의 요청과 일치하지 않으면, Kubernetes 서비스는 다음 역할을 확인하며, 이런 식으로 계속됩니다.

Kubernetes 서비스가 클러스터의 모든 라벨과 요청의 리소스와 일치하는 spec.allow 조건을 가진 역할을 찾으면, 해당 역할의 allow.kubernetes_groupsallow.kubernetes_users 필드를 조회합니다. 이후 임퍼소네이션 헤더를 작성하는 데 사용할 RBAC 프린시펄 목록에 이러한 값을 추가합니다.

다음으로 Kubernetes 서비스는 사용자의 각 역할에서 spec.deny 조건을 확인합니다. 한 역할의 spec.deny.kubernetes_labels 또는 spec.deny.kubernetes_resources 필드가 사용자의 요청과 일치하면, Kubernetes 서비스는 해당 역할의 spec.deny.kubernetes_groupsspec.deny.kubernetes_users 필드를 조회합니다. 이전에 생성한 사용자와 그룹 목록에서 이러한 값을 각각 제거하여, 사용자가 이러한 RBAC 프린시펄에 접근하지 못하도록 거부합니다.

예시#

사용자에게 다음 세 가지 역할이 할당되어 있다고 가정해 보겠습니다:

kind: role
metadata:
  name: allow-dev-us-east-2
version: v7
spec:
  allow:
    kubernetes_labels:
      "region": "us-east-2"
    kubernetes_resources:
      - kind: pod
        namespace: "development"
        name: "redis-*"
      - kind: pod
        namespace: "development"
        name: "nginx-*"
    kubernetes_groups:
      - dev-viewers # 사용자가 development 네임스페이스에서 파드를 볼 수 있도록 허용합니다
---
kind: role
metadata:
  name: allow-exec
version: v7
spec:
  allow:
    kubernetes_labels:
        "*": "*"
    kubernetes_resources:
      - kind: pod
        namespace: "*"
        name: "*"
    kubernetes_groups:
      - executors # 사용자가 모든 파드에 대해 명령을 실행할 수 있도록 허용합니다
---
kind: role
metadata:
  name: deny-redis-exec
version: v7
spec:
  deny:
    kubernetes_resources:
      - kind: pod
        namespace: "*"
        name: "redis-*"
    kubernetes_groups:
      - executors

dev-viewers Kubernetes 그룹은 사용자가 development 네임스페이스의 파드를 볼 수 있도록 허용합니다. executors Kubernetes 그룹은 사용자가 모든 네임스페이스의 모든 파드에 대해 명령을 실행할 수 있도록 허용합니다.

이러한 역할을 가진 사용자가 development 네임스페이스에서 kubectl get pods/redis-1을 실행하고 클러스터에 region:us-east-2 라벨이 있는 경우, Kubernetes 서비스는 요청을 수락합니다. deny-redis-exec 역할이 redis-* 파드에 대해 executors 그룹을 거부하기 때문에, Kubernetes 서비스는 dev-viewers 그룹은 임퍼소네이트하지만 executors 그룹은 임퍼소네이트하지 않은 상태로 요청을 전달합니다.

그러나 동일한 사용자가 동일한 클러스터에 대해 development 네임스페이스에서 kubectl exec -it nginx /bin/bash를 실행하면, deny-redis-exec 역할의 deny 조건이 요청과 일치하지 않으므로 Kubernetes 서비스는 dev-viewersexecutors 그룹 모두에 대한 임퍼소네이션 헤더로 요청을 전달합니다.

리소스에 대한 접근을 점진적으로 활성화#

Teleport와 Kubernetes RBAC를 설계하여 제한된 Kubernetes 리소스 부분 집합에 대한 접근을 점진적으로 허용할 수 있습니다. 다시 말해, 사용자는 Kubernetes 클러스터의 광범위한 리소스에 제한된 접근 권한을 갖게 됩니다. 이러한 사용자의 부분 집합은 더 제한된 리소스 집합에 더 큰 접근 권한을 갖게 됩니다. 이러한 사용자의 부분 집합 중에서, 다른 리소스 집합에 대해 더 작은 그룹에 더 큰 접근 권한을 할당할 수 있으며, 이런 식으로 계속됩니다.

이를 위해 다음과 같은 여러 Teleport 역할을 정의합니다:

그런 다음 서로 다른 사용자에게 역할의 조합을 할당할 수 있습니다.

예를 들어, 다음 역할 조합은 사용자가 등록된 모든 Kubernetes 클러스터에서 모든 파드를 볼 수 있도록 허용하지만, nginx-* 파드에서만 kubectl exec 또는 kubectl logs를 실행할 수 있도록 합니다:

kind: role
metadata:
  name: kube-viewer
version: v7
spec:
  allow:
    kubernetes_labels:
      '*': '*'
    kubernetes_resources:
      - kind: pod
        namespace: "*"
        name: "*"
    kubernetes_groups:
    - viewer # 파드를 가져오고 목록을 조회할 수 있지만 명령 실행이나 로그 검색은 할 수 없습니다
---
kind: role
metadata:
  name: nginx-exec
version: v7
spec:
  allow:
    kubernetes_labels:
      '*': '*'
    kubernetes_resources:
      - kind: pod
        namespace: "*"
        name: "nginx-*"
    kubernetes_groups:
    - execAndLogs

이 경우, kube-viewer 역할은 사용자를 Kubernetes viewer 그룹에 매핑하여, 사용자가 파드를 가져오고 목록을 조회할 수 있지만 명령을 실행하거나 로그를 검색할 수는 없도록 합니다. nginx-exec 역할을 사용하면, 사용자는 명령을 실행하고 로그를 검색할 수 있는 execAndLogs 그룹에 접근할 수 있지만, nginx 파드에서만 가능합니다.

이 설정에서는 Teleport 사용자의 요구 사항에 따라 kube-viewer 역할을 파드의 부분 집합에 대한 상승된 접근 권한을 부여하는 다른 역할과 결합할 수도 있습니다.

보안 고려 사항: 리소스 네임스페이스 제한#

Teleport 사용자가 예를 들어 kubectl get pods로 파드 목록 조회 요청을 보내면, Teleport Kubernetes 서비스는 다음을 수행합니다:

의도치 않게 리소스가 유출되는 것을 방지하려면, Kubernetes RBAC의 네임스페이스 제한이 Teleport에 설정한 제한과 일치하는지 확인해야 합니다.

예를 들어, 사용자가 어떤 네임스페이스의 어떤 파드에도 접근을 허용하는 Teleport 역할을 가지고 있고, 해당 사용자를 default-pod-viewer Kubernetes 그룹에 매핑한다고 가정해 보겠습니다. 이 그룹은 default 네임스페이스의 파드만 볼 수 있습니다:

kind: role
metadata:
  name: kube-access-1
version: v7
spec:
  allow:
    kubernetes_groups:
      - default-pod-viewer
    kubernetes_resources:
      - kind: pod
        namespace: "*"
        name: "*"
    # ...

사용자는 두 번째 Teleport 역할을 가지고 있으며, 이는 사용자를 system:masters Kubernetes 그룹(모든 네임스페이스의 모든 파드에 접근 가능)에 매핑하고, default 네임스페이스의 webapp 파드에만 접근 권한을 부여합니다:

metadata:
  name: kube-access-2
version: v7
spec:
  allow:
    kubernetes_groups:
      - system:masters
    kubernetes_resources:
      - kind: pod
        namespace: "default"
        name: "webapp"
    # ...

kube-access-2 역할이 사용자를 system:masters에 매핑하므로, Kubernetes 서비스가 이 사용자로부터 요청을 전달할 때 요청의 임퍼소네이션 헤더에 system:masters 그룹을 추가하여 Kubernetes 클러스터에서 모든 파드를 가져옵니다.

그러나 사용자는 모든 네임스페이스의 모든 파드에 대한 접근을 허용하는 역할(kube-access-1)도 가지고 있으므로, Kubernetes 서비스는 API 서버에 대한 첫 번째 요청을 통해 가져온 파드를 필터링하지 않습니다.

즉, Kubernetes 서비스는 Teleport가 default 네임스페이스의 webapp 파드에만 접근을 허용하기 위해 사용자를 system:masters 그룹에 매핑했다는 것을 알 방법이 없습니다.

Teleport RBAC에 네임스페이스 제한이 있는 경우, Teleport 사용자에게 매핑하는 Kubernetes RBAC 리소스에도 동일한 네임스페이스 제한이 있는지 확인해야 합니다.

예를 들어, 다음과 같은 권한을 갖도록 kube-access-1 역할을 다시 작성하여 사용자를 default 네임스페이스의 파드로 제한해야 합니다:

kind: role
metadata:
  name: kube-access-1
version: v7
spec:
  allow:
    kubernetes_groups:
      - default-pod-viewer
    kubernetes_resources:
      - kind: pod
        namespace: "default"
        name: "*"
    # ...

Teleport Kubernetes 접근 제어

Teleport v18.9
원문 보기
요약

이 가이드는 Teleport Kubernetes 서비스가 Teleport 사용자가 Kubernetes 클러스터와 상호 작용할 때 역할 기반 접근 제어를 적용하는 방법을 설명합니다. 이 가이드에서는 Teleport에 연결한 Kubernetes 클러스터에 대한 접근을 관리하기 위해 Teleport 역할 내에서 사용 가능한 필드를 구성하는 방법을 보여드립니다.

이 가이드는 Teleport Kubernetes 서비스가 Teleport 사용자가 Kubernetes 클러스터와 상호 작용할 때 역할 기반 접근 제어를 적용하는 방법을 설명합니다. Kubernetes 서비스는 Kubernetes API 서버에 대한 요청을 가로채고 사용자의 Teleport 역할에 따라 각 요청을 수정합니다.

이 가이드에서는 Teleport에 연결한 Kubernetes 클러스터에 대한 접근을 관리하기 위해 Teleport 역할 내에서 사용 가능한 필드를 구성하는 방법을 보여드립니다.

로컬 minikube 클러스터를 사용하여 Kubernetes로 Teleport 역할을 사용하는 방법의 예시는 RBAC 방법 가이드를 참조하세요.

Kubernetes 접근을 관리하는 역할 필드#

이 섹션에서는 Kubernetes 클러스터에 대한 접근을 구성하는 Teleport 역할 내 필드를 설명합니다.

Kubernetes 클러스터에 대한 접근을 관리하려면 Teleport 역할이 spec.allow 섹션에 다음 필드를 포함해야 합니다:

다음은 Kubernetes 클러스터에 대한 접근을 제한하는 Teleport 역할의 예시입니다:

kind: role
metadata:
  name: kube-access
version: v8
spec:
  allow:
    kubernetes_labels:
      region: '*'
      platform: minikube
    kubernetes_resources:
      - kind: pods
        namespace: production
        name: '^webapp-[a-z0-9-]+$'
        api_group: ''
      - kind: pods
        namespace: development
        name: '*'
        api_group: ''
      - kind: deployments
        namespace: development
        name: '*'
        api_group: apps
    kubernetes_groups:
    - developers
    kubernetes_users:
    - minikube
  deny: {}

kubernetes_labels#

Kubernetes 클러스터를 Teleport에 등록할 때 라벨을 추가할 수 있습니다. 역할의 kubernetes_labels 필드를 사용하여 서로 다른 라벨을 가진 Kubernetes 클러스터에 대한 사용자의 접근을 제한할 수 있습니다.

kind: role
metadata:
  name: kube-access
version: v8
spec:
  allow:
    kubernetes_labels:
      region: '*'
      environment: development
      # ...
  deny: {}

kubernetes_labels 필드의 값은 라벨 에서 하나 이상의 라벨 (즉, 문자열 또는 목록)으로의 매핑입니다.

Kubernetes 서비스가 kubernetes_labels를 평가하는 방식#

라벨의 키와 값이 모두 와일드카드, *인 경우, Teleport Kubernetes 서비스는 모든 라벨을 가진 Kubernetes 클러스터에 대한 접근을 사용자에게 허용합니다:

spec:
  allow:
    kubernetes_labels:
      '*': '*'
    # ...

그렇지 않은 경우, Kubernetes 서비스는 kubernetes_labels의 모든 키가 등록된 Kubernetes 클러스터에 해당하는 키와 일치하는지 확인합니다. 일치하지 않으면 일치하는 Kubernetes 클러스터가 없으므로 Kubernetes 서비스는 요청을 거부합니다.

예를 들어, environment 키는 포함하지만 region 키는 포함하지 않는 라벨을 가진 클러스터는 위의 kube-access 역할에서 kubernetes_labels 필드와 일치하지 않습니다.

그런 다음 Kubernetes 서비스는 kubernetes_labels의 키에 해당하는 Kubernetes 클러스터 라벨의 값을 가져옵니다. kubernetes_labels의 각 키 값은 Kubernetes 서비스가 사용자에게 클러스터 접근을 허용하기 전에 Kubernetes 클러스터 라벨의 값과 반드시 일치해야 합니다.

예를 들어, 위의 kube-access 역할은 region 키가 있고 어떤 값을 가지든 사용자가 Kubernetes 클러스터에 접근하도록 허용합니다. 이 역할은 사용자를 environment 키가 있고 development 값을 가진 Kubernetes 클러스터로 제한합니다. kubernetes_labels 내 키의 유효한 값에 대해서는 다음 섹션에서 설명합니다.

라벨 값#

kubernetes_labels의 라벨 키가 Kubernetes 클러스터의 키와 일치하려면 정확히 일치해야 합니다. 그러나 값의 경우, 유연성을 제공하기 위해 정규 표현식, 와일드카드, 여러 값을 구성할 수 있습니다.

정규 표현식과 와일드카드#

문자열의 부분 집합이나 변형을 일치시키기 위해 정규 표현식 또는 와일드카드 문자를 사용할 수 있습니다. 값이 ^로 시작하고 $로 끝나면, Kubernetes 서비스는 이를 Go의 re2 구문을 사용하는 정규 표현식으로 처리합니다(re2 README 참조).

그렇지 않으면 Kubernetes 서비스는 값 내에서 와일드카드를 평가하여 라벨의 임의 문자 시퀀스와 일치시킵니다.

다음은 예시입니다:

spec:
  allow:
    kubernetes_labels:
      region: 'us-east-*'
      team: '^data-eng-[a-z-]+$'
    # ...

allow 규칙은 region:us-east-1region:us-east-2b 라벨을 가진 클러스터와 일치합니다. 또한 team:data-eng-analyticsteam:data-eng-ml-training 라벨을 가진 클러스터와도 일치합니다.

여러 값#

kubernetes_labels의 키에 여러 값이 있는 경우, Kubernetes 서비스는 이러한 값 중 어느 하나라도 Kubernetes 클러스터의 라벨과 일치하면 라벨 값이 일치하는 것으로 간주합니다. 예를 들어, 다음 kubernetes_labels 구성은 region:us-east-2 라벨과 development 또는 staging 환경 중 하나를 가진 클러스터와 일치합니다:

spec:
  allow:
    kubernetes_labels:
      region: 'us-east-*'
      environment: ['development', 'staging']
    # ...

라벨 적용#

Teleport Kubernetes 서비스 인스턴스에 라벨을 적용할 수 있습니다. 그 방법은 서비스를 실행한 방식에 따라 다릅니다:

teleport-kube-agent Helm 차트를 설치하거나 업그레이드할 때 라벨을 설정합니다. 예시:

$ helm upgrade teleport-agent teleport/teleport-kube-agent --set kubeClusterName=${CLUSTER?}\
  --set proxyAddr=${PROXY?} --set authToken=${TOKEN?} --create-namespace --namespace=teleport-agent\
  --set labels.env=prod --set labels.region=us-west-1

teleport 인스턴스의 구성 파일에서 Teleport Kubernetes 서비스를 활성화할 때 라벨을 설정합니다:

kubernetes_service:
  enabled: true
  kube_cluster_name: cookie
  labels:
    env: prod
    region: us-west-1

kubernetes_groupskubernetes_users#

Teleport Kubernetes 서비스는 예를 들어 kubectl을 통해 최종 사용자로부터 요청을 받아 Kubernetes API 서버로 전달합니다. Kubernetes 서비스는 임퍼소네이션 헤더를 사용하여 하나의 Kubernetes 사용자와 0개 이상의 Kubernetes 그룹으로 API 서버에 요청을 전송합니다.

Impersonation

kubernetes_userskubernetes_groups 필드는 사용자가 Kubernetes API 서버에 요청을 보낼 때 어떤 사용자와 그룹을 사용자가 가정하도록 허용할지 나타냅니다:

kind: role
metadata:
  name: kube-access
version: v7
spec:
  allow:
    kubernetes_groups:
    - developers
    - viewers
    kubernetes_users:
    - myuser
    - system:serviceaccount:someNamespace:saName # 서비스 계정 이름
    # ...
  deny: {}

kubernetes_groupskubernetes_users의 값은 임퍼소네이션을 활성화할 그룹, 사용자, 또는 서비스 계정의 이름 목록입니다.

Kubernetes 사용자와 그룹#

Kubernetes 사용자와 그룹은 Kubernetes 클러스터에 존재하는 엔티티이며, ClusterRoleBinding 또는 RoleBinding 리소스를 통해 권한이 제어됩니다. 클러스터에 존재하지 않는 경우, Kubernetes RBAC은 이를 무시합니다.

다음은 내장된 view ClusterRolecluster-viewer-group 그룹과 cluster-viewer-user 사용자에게 할당하는 ClusterRoleBinding 리소스의 예시입니다:

apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
  name: cluster-viewer
roleRef:
  apiGroup: rbac.authorization.k8s.io
  kind: ClusterRole
  name: view
subjects:
- apiGroup: rbac.authorization.k8s.io
  kind: Group
  name: cluster-viewer-group
- apiGroup: rbac.authorization.k8s.io
  kind: User
  name: cluster-viewer-user

이 시점에서 사용자와 그룹은 Kubernetes 네임스페이스의 리소스를 볼 수 있는 동일한 권한을 갖습니다. Kubernetes는 요청에 사용된 임퍼소네이션 프린시펄과 관련된 권한을 병합하기 때문에, Kubernetes 사용자와 그룹에 동일한 권한을 할당하는 것이 필수는 아닙니다.

Kubernetes 서비스 계정#

Teleport는 kubernetes_users 필드에 서비스 계정의 정규화된 이름을 사용하여 서비스 계정 임퍼소네이션을 지원합니다.

서비스 계정의 정규화된 이름은 다음 패턴으로 구성됩니다:

system:serviceaccount:<namespace>:<service_account_name>

FQN은 system:serviceaccount:로 시작해야 합니다. 그렇지 않으면 Kubernetes는 이를 일반 사용자로 평가합니다.

서비스 계정을 임퍼소네이트하는 역할의 예시는 다음과 같습니다.

kind: role
metadata:
  name: kube-access-impersonate-sa
version: v7
spec:
  allow:
    kubernetes_users:
    - system:serviceaccount:someNamespace:saName
    # ...
  deny: {}

Teleport 사용자가 Kubernetes 사용자, 그룹, 서비스 계정을 임퍼소네이트하는 방법#

최종 사용자가 임퍼소네이트할 사용자 또는 서비스 계정과 그룹을 지정하는 방법에는 두 가지가 있습니다:

수동으로#

사용자가 Kubernetes 클러스터에 인증하기 위해 tsh kube login을 실행할 때, --as--as-groups 플래그를 사용하여 인증할 사용자와 그룹을 수동으로 지정할 수 있습니다. Teleport Kubernetes 서비스는 해당 사용자와 그룹이 사용자의 kubernetes_userskubernetes_groups 구성에 속하는지 확인하고, 그렇지 않은 경우 사용자의 접근을 거부합니다.

자동으로#

클러스터에 인증할 때 사용자가 Kubernetes 사용자와 Kubernetes 그룹을 명시적으로 지정하지 않은 경우, Teleport Kubernetes 서비스는 사용자 역할의 kubernetes_userskubernetes_groups 필드로부터 이를 결정합니다.

사용자가 kubernetes_users에 정확히 하나의 값을 가지고 있으면, Teleport Kubernetes 서비스는 해당 사용자를 임퍼소네이트합니다. kubernetes_users에 값이 없거나 와일드카드(*)가 있으면, Kubernetes 서비스는 사용자의 Teleport 사용자 이름을 사용합니다.

사용자가 여러 개의 kubernetes_users를 가지고 있고 클러스터에 인증할 때 하나를 지정하지 않은 경우(즉, 이전 섹션에서 설명한 --as 플래그를 사용하지 않은 경우), Kubernetes 서비스는 요청을 거부합니다.

사용자가 임퍼소네이트할 Kubernetes 그룹을 지정하지 않은 경우, Kubernetes 서비스는 kubernetes_groups 내의 모든 값을 사용합니다.

Warning

권한이 낮은 사용자를 임퍼소네이트할 때, 특정 그룹을 수동으로 임퍼소네이트하지 않는 한 (예: --as-groups 플래그 사용), Kubernetes 서비스는 kubernetes_groups 내의 모든 그룹을 자동으로 임퍼소네이트한다는 점을 기억하세요.

이는 사용자와 자동으로 임퍼소네이트된 그룹 모두의 결합된 권한을 갖게 되므로 혼란을
일으킬 수 있습니다.

위의 kube-access 역할을 사용하면, Teleport에 인증한 후 Kubernetes 서비스는 임퍼소네이션 헤더를 사용하여 developers 그룹과 myuser Kubernetes 사용자로 요청을 API 서버에 전달합니다.

임퍼소네이션 활성화#

Kubernetes 서비스가 임퍼소네이션 헤더로 사용자 요청을 전달하도록 활성화하려면, 서비스 계정이 클러스터 내에서 Kubernetes RBAC 프린시펄을 임퍼소네이트할 권한을 갖도록 해야 합니다. Kubernetes 서비스는 사용자가 접근 권한이 없는 사용자 또는 그룹을 임퍼소네이트하려는 요청을 거부합니다.

아래는 임퍼소네이션을 활성화하는 데 필요한 최소 권한 집합을 부여하는 Kubernetes ClusterRole과, 이러한 권한을 서비스 계정에 부여하는 ClusterRoleBinding입니다.

Tip

일반적으로 이러한 리소스를 수동으로 정의할 필요는 없습니다. Kubernetes 클러스터를 Teleport에 등록하는 수동 방법자동 방법에는 Teleport가 클러스터 접근을 허용하기 위해 필요한 Kubernetes RBAC 리소스를 설정하는 단계가 포함되어 있습니다.

apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
  name: teleport-impersonation
rules:
- apiGroups:
  - ""
  resources:
  - users
  - groups
  - serviceaccounts
  verbs:
  - impersonate
- apiGroups:
  - ""
  resources:
  - pods
  verbs:
  - get
- apiGroups:
  - "authorization.k8s.io"
  resources:
  - selfsubjectaccessreviews
  verbs:
  - create
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
  name: teleport
roleRef:
  apiGroup: rbac.authorization.k8s.io
  kind: ClusterRole
  name: teleport-impersonation
subjects:
- kind: ServiceAccount
  name: teleport-serviceaccount
  namespace: default

사용자 트레이트를 기반으로 그룹과 사용자 지정#

Teleport 역할에 이 정보를 하드코딩하는 대신, 각 Teleport 사용자별로 개별적으로 Kubernetes 그룹과 사용자를 지정할 수 있습니다. 이를 위해 Teleport 역할에 템플릿 변수를 추가할 수 있으며, Teleport Auth 서비스가 인증하는 각 사용자의 정보로 이를 채웁니다.

Teleport 역할에서 템플릿 변수 확장이 작동하는 방식에 대한 자세한 내용은 Access Controls Reference를 참조하세요.

싱글 사인온 제공업체 트레이트#

Teleport의 역할은 템플릿 변수를 사용하여 OIDC 클레임 또는 SAML 속성을 매핑합니다. Teleport Auth 서비스는 {{external.*}} 형식의 템플릿 변수를 해당하는 SAML 속성 또는 OIDC 클레임으로 대체합니다:

kind: role
version: v7
metadata:
  name: group-member
spec:
  allow:
    kubernetes_groups: ["{{external.groups}}"]
    kubernetes_users: ["{{external.kube_username}}"]
    # ...

예를 들어, 사용자가 SAML 커넥터를 통해 Teleport에 인증하고, 해당 사용자가 값이 myuserkube_username 속성과 값이 developersviewersgroups 속성을 가지고 있는 경우, 위의 group-member 역할은 다음과 같이 평가됩니다:

kind: role
version: v7
metadata:
  name: group-member
spec:
  allow:
    kubernetes_groups: ["developers", "viewers"]
    kubernetes_users: ["myuser"]
    # ...
로컬 사용자 트레이트#

로컬 사용자의 경우, user 리소스의 spec.traits 필드에 임의의 키-값 데이터를 지정한 다음, 역할에서 {{external.*}} 템플릿 변수를 사용하여 해당 트레이트를 참조할 수 있습니다.

예를 들어, 다음 역할은 내부 트레이트로 kubernetes_userskubernetes_groups를 채웁니다:

kind: role
version: v7
metadata:
  name: group-member
spec:
  allow:
    kubernetes_groups: ["{{external.groups}}"]
    kubernetes_users: ["{{external.kube_username}}"]
    # ...

그런 다음 로컬 사용자를 생성하거나 수정할 때 이러한 템플릿 변수에 대한 값을 제공할 수 있습니다. 예를 들어, 다음 사용자 정의에는 Auth 서비스가 위의 역할 정의를 채우는 데 사용할 트레이트가 포함되어 있습니다:

kind: user
version: v2
metadata:
  name: alice
spec:
  roles:
    - group-member
  traits:
    groups:
      - developers
      - viewers
    kube_username:
      - myuser

적시 접근(just-in-time access) 구성#

특정 Kubernetes 리소스에 대한 적시 접근을 활성화하기 위해 Teleport 역할을 설정하는 경우, Teleport가 접근을 제한할 수 있는 Kubernetes 리소스 외에는 Kubernetes 리소스에 대한 접근 권한이 없는 프린시펄로 역할의 kubernetes_groupskubernetes_users를 설정해야 합니다.

이는 사용자가 Kubernetes 파드에 대한 접근을 요청하고 요청이 승인되면, Teleport Kubernetes 서비스가 역할의 kubernetes_groupskubernetes_users 필드를 사용하여 Kubernetes API 서버에 대한 사용자 요청에 임퍼소네이션 헤더를 추가하기 때문입니다. 이러한 조건에서 Teleport는 원하는 pod를 제외한 지원되는 모든 Kubernetes 리소스 종류에 대한 접근을 제한할 수 있습니다.

Teleport는 네임스페이스 범위의 커스텀 리소스에 대한 접근도 제한할 수 있지만, 클러스터 범위의 커스텀 리소스는 제한할 수 없습니다. 클러스터 범위인 CRD 리소스는 kubernetes_userskubernetes_groups 필드의 프린시펄이 접근 권한을 가지고 있으면 사용자에게 접근 가능합니다.

Kubernetes 네임스페이스에 대한 접근을 요청하면 해당 네임스페이스의 모든 리소스에 접근할 수 있지만, 클러스터의 다른 지원되는 리소스에는 접근할 수 없습니다.

kubernetes_resources#

kubernetes_resources 필드는 Teleport 역할이 Kubernetes 클러스터의 특정 리소스에 대한 접근을 구성할 수 있도록 합니다.

이 필드의 값은 매핑 목록이며, 각 매핑은 다음과 같이 설명됩니다:

역할 V8#

Warning

역할 V8은 커스텀 리소스 정의(CRD)를 포함하여 모든 Kubernetes 리소스 종류에 대한 접근 관리를 지원합니다. 이를 위해 이전 역할 버전에 비해 kubernetes_resources 섹션이 처리되는 방식에 여러 변경 사항이 있습니다:

  • kind 필드는 항상 리소스 종류의 복수 형태를 지정해야 합니다
  • 핵심 API 그룹에 속하지 않는 리소스에는 api_group 필드를 설정해야 합니다
  • kind: namespaces는 이제 네임스페이스 리소스와 일치하며, 네임스페이스 내의 리소스와는 더 이상 일치하지 않습니다
  • namespace 필드가 설정되고 값이 * 이외인 경우 클러스터 범위 리소스와 일치하지 않습니다

이 동작은 이전 역할 버전과 다르므로, 이전 버전에서 V8로 역할을 마이그레이션하는 경우 kubernetes_resources 섹션을 조정해야 할 가능성이 높습니다.

kind: role
metadata:
  name: kube-access
version: v8
spec:
  allow:
    kubernetes_labels:
      "*": "*"
    kubernetes_resources:
      - kind: pods
        api_group: ""
        namespace: production
        name: webapp
        verbs: ["*"]
      - kind: deployments
        api_group: apps
        namespace: development
        name: "*"
    # ...
  • kind: 접근을 활성화할 리소스의 종류입니다. * 또는 종류의 복수 형태(예: pods, deployments, cronjobs, mycustomresources)일 수 있습니다. 리소스에 그룹이 있는 경우 api_group 필드에 지정해야 합니다. 예를 들어, pods는 그룹이 필요하지 않지만 deploymentsapi_group 필드를 apps로 설정해야 합니다.
    Tip

다음 명령을 실행하여 사용 가능한 리소스의 전체 목록과 해당 API 그룹을 확인할 수 있습니다:

$ kubectl api-resources --namespaced=true -o=name
$ kubectl api-resources --namespaced=false -o=name
  • 해당 줄에 .이 있으면, 종류는 . 앞의 첫 번째 요소이고 API 그룹은 첫 번째 . 이후의 모든 부분입니다.
  • 해당 줄에 .이 없으면, 종류는 전체 요소이며 API 그룹은 없습니다.
Warning

와일드카드 *를 사용하면 클러스터 범위 리소스를 포함하여(종류/api_group 기준) 모든 리소스와 일치한다는 점에 유의하세요. 빈 문자열 ""을 사용하면 클러스터 범위 리소스와만 일치합니다. ^.+$와 같은 다른 값은 네임스페이스가 지정된 리소스와만 일치하고 클러스터 범위 리소스는 제외합니다.

namespace, name, api_group 필드에는 와일드카드 문자(*)를 추가하여 임의의 문자 시퀀스를 대체할 수 있습니다. 예를 들어, name: "pod-*-*"pod-1-apod-2-c라는 이름의 파드와 일치합니다. kubernetes_labels와 마찬가지로, 값이 ^로 시작하고 $로 끝나면 Kubernetes 서비스는 이를 Go의 re2 구문을 사용하는 정규 표현식으로 처리합니다 (re2 README 참조).

Tip

역할의 kubernetes_resources 필드에 이름이 지정된 파드에 사용자가 접근하려면, 사용자는 kubernetes_groups 또는 kubernetes_users 내에 적어도 하나의 값을 포함하는 Teleport 역할이 할당되어 있어야 합니다. Teleport는 접근을 허용하거나 거부하기 위해 Kubernetes 역할을 변경하지 않습니다. Kubernetes 서비스가 클러스터 내 파드에 대한 접근을 허용하거나 거부하기 위해 Teleport 역할을 평가하는 방식에 대한 설명은 다음 섹션을 참조하세요.

역할 V7#

Tip

역할 V7은 더 많은 kind 값에 대한 지원을 추가했습니다. 단수 이름을 사용하며, 이후 역할 버전에서는 복수 형태를 사용합니다.

Warning

와일드카드(*)와 namespace 종류는 특별한 의미를 가지므로, 이를 사용할 때는 의도와 이후 버전과의 동작 차이에 특별히 주의해야 합니다.

kind: role
metadata:
  name: kube-access
version: v7
spec:
  allow:
    kubernetes_labels:
      "*": "*"
    kubernetes_resources:
      - kind: pod
        namespace: production
        name: webapp
        verbs: ["*"]
    # ...

* 종류의 동작은 이후 버전과 약간 다릅니다. V7에서는 namespace 필드와 관계없이 클러스터 범위 리소스를 포함한 모든 리소스에 대한 접근을 허용합니다. 이후 역할 버전에서는 namespace 필드가 강제되므로, 업그레이드할 때 특히 deny 쪽에서 리소스를 조정해야 할 수 있습니다.

Warning

namespace 종류는 namespace 리소스 자체는 물론 그 안의 모든 리소스도 다룹니다. 이는 이후 역할 버전에서 리소스 자체만 다루는 것과 다른 동작이므로, 업그레이드할 때 특히 deny 쪽에서 리소스를 조정해야 할 수 있습니다.

Kind 부여하는 접근 권한
* namespace 필드와 관계없이 클러스터 범위 리소스를 포함한 모든 리소스
pod 파드
secret 시크릿
configmap ConfigMap
namespace 네임스페이스 및 그 안의 모든 리소스
service 서비스
serviceaccount 서비스 계정
kube_node 노드
persistentvolume PersistentVolume
persistentvolumeclaim PersistentVolumeClaim
deployment 디플로이먼트
replicaset ReplicaSet
statefulset StatefulSet
daemonset DaemonSet
clusterrole ClusterRole
kube_role Role
clusterrolebinding ClusterRoleBinding
rolebinding RoleBinding
cronjob CronJob
job Job
certificatesigningrequest CertificateSigningRequest
ingress Ingress

namespacename 필드 모두에 와일드카드 문자(*)를 추가하여 임의의 문자 시퀀스를 대체할 수 있습니다. 예를 들어, name: "pod-*-*"pod-1-apod-2-c라는 이름의 파드와 일치합니다. kubernetes_labels와 마찬가지로, 값이 ^로 시작하고 $로 끝나면 Kubernetes 서비스는 이를 Go의 re2 구문을 사용하는 정규 표현식으로 처리합니다(re2 README 참조).

Tip

역할의 kubernetes_resources 필드에 이름이 지정된 파드에 사용자가 접근하려면, 사용자는 kubernetes_groups 또는 kubernetes_users 내에 적어도 하나의 값을 포함하는 Teleport 역할이 할당되어 있어야 합니다. Teleport는 접근을 허용하거나 거부하기 위해 Kubernetes 역할을 변경하지 않습니다. Kubernetes 서비스가 클러스터 내 파드에 대한 접근을 허용하거나 거부하기 위해 Teleport 역할을 평가하는 방식에 대한 설명은 다음 섹션을 참조하세요.

역할 V6#

Tip

역할 V6은 kubernetes_resources 필드에 대한 지원을 도입했지만, 종류가 'pod'인 파드에 대한 접근만 허용하도록 제한되었습니다. 이후 역할 버전에서 추가 리소스에 대한 지원이 확장되었습니다.

kind: role
metadata:
  name: kube-access
version: v6
spec:
  allow:
    kubernetes_labels:
      "*": "*"
    kubernetes_resources:
      - kind: pod
        namespace: production
        name: webapp
    # ...

namespacename 필드 모두에 와일드카드 문자(*)를 추가하여 임의의 문자 시퀀스를 대체할 수 있습니다. 예를 들어, name: "pod-*-*"pod-1-apod-2-c라는 이름의 파드와 일치합니다. kubernetes_labels와 마찬가지로, 값이 ^로 시작하고 $로 끝나면 Kubernetes 서비스는 이를 Go의 re2 구문을 사용하는 정규 표현식으로 처리합니다(re2 README 참조).

Tip

역할의 kubernetes_resources 필드에 이름이 지정된 파드에 사용자가 접근하려면, 사용자는 kubernetes_groups 또는 kubernetes_users 내에 적어도 하나의 값을 포함하는 Teleport 역할이 할당되어 있어야 합니다. Teleport는 접근을 허용하거나 거부하기 위해 Kubernetes 역할을 변경하지 않습니다. Kubernetes 서비스가 클러스터 내 파드에 대한 접근을 허용하거나 거부하기 위해 Teleport 역할을 평가하는 방식에 대한 설명은 다음 섹션을 참조하세요.

예시#

production을 제외한 네임스페이스가 지정된 리소스에 대한 전체 접근#

다음 역할은 production 네임스페이스를 제외한 모든 네임스페이스의 모든 네임스페이스가 지정된 리소스에 대한 전체 접근을 부여하며, production에서는 어떤 리소스에도 접근할 수 없습니다.

kind: role
metadata:
  name: kube-access
version: v7
spec:
  allow:
    kubernetes_labels:
      "*": "*"
    kubernetes_resources:
      # v7에서 namespace는 네임스페이스 내의 모든 것을 의미합니다.
      - kind: namespace  # v7은 단수형을 사용합니다.
        name: "*"
        verbs: ["*"]
  deny:
    kubernetes_resources:
      - kind: namespace  # v7은 단수형을 사용합니다.
        name: production
        verbs: ["*"]
    # ...
kind: role
metadata:
  name: kube-access
version: v8
spec:
  allow:
    kubernetes_labels:
      "*": "*"
    kubernetes_resources:
      # 모든 네임스페이스에서 네임스페이스가 지정된 리소스에 대한 접근을 부여합니다.
      - kind: "*"
        api_group: "*"
        name: "*"
        namespace: "^.+$"  # 네임스페이스가 지정된 모든 리소스와 일치하며, 클러스터 범위 리소스는 일치하지 않습니다.
        verbs: ["*"]
      # 네임스페이스 리소스 자체에 대한 접근을 부여합니다.
      - kind: namespaces  # v8에서 namespaces는 네임스페이스 자체를 의미합니다. 클러스터 범위 리소스로 간주되므로 별도로 추가해야 합니다.
        name: "*"
        verbs: ["*"]
  deny:
    kubernetes_resources:
      # production 네임스페이스의 네임스페이스가 지정된 리소스에 대한 접근을 거부합니다.
      - kind: "*"
        api_group: "*"
        name: "*"
        namespace: production
        verbs: ["*"]
      # 네임스페이스 리소스 자체에 대한 접근을 거부합니다.
      - kind: namespaces  # v8은 복수형을 사용합니다.
        name: production
        verbs: ["*"]
    # ...

또는 다음과 같이 사용할 수도 있습니다:

kind: role
metadata:
  name: kube-access
version: v8
spec:
  allow:
    kubernetes_labels:
      "*": "*"
    kubernetes_resources:
      # 모든 항목에 대한 전체 접근을 부여합니다.
      - kind: "*"
        api_group: "*"
        name: "*"
        namespace: "*"  # v8에서 '*'는 네임스페이스가 지정된 리소스와 클러스터 범위 리소스 모두와 일치합니다.
        verbs: ["*"]
  deny:
    kubernetes_resources:
      # 클러스터 범위 리소스에 대한 접근을 거부합니다.
      - kind: "*"
        api_group: "*"
        name: "*"
        namespace: ""  # 빈 네임스페이스는 클러스터 범위 리소스만 일치함을 의미합니다.
        verbs: ["*"]
      # production 네임스페이스의 네임스페이스가 지정된 리소스에 대한 접근을 거부합니다.
      - kind: "*"
        api_group: "*"
        name: "*"
        namespace: production
        verbs: ["*"]
      # 네임스페이스 리소스 자체에 대한 접근을 거부합니다.
      - kind: namespaces  # v8은 복수형을 사용합니다.
        name: production
        verbs: ["*"]
    # ...
dev 네임스페이스와 clusterroles를 제외한 모든 클러스터 범위 리소스에 대한 전체 접근#

다음 역할은 dev 네임스페이스의 모든 리소스와 clusterroles를 제외한 모든 클러스터 범위 리소스에 대한 접근을 부여합니다.

kind: role
metadata:
  name: kube-access
version: v7
spec:
  allow:
    kubernetes_labels:
      "*": "*"
    kubernetes_resources:
      # v7에서 "*"는 네임스페이스와 관계없이 클러스터 범위 리소스를 포함합니다.
      - kind: "*"
        name: "*"
        namespace: dev
        verbs: ["*"]
  deny:
    kubernetes_resources:
      - kind: clusterrole  # v7은 단수형을 사용합니다.
        name: "*"
        verbs: ["*"]
    # ...
kind: role
metadata:
  name: kube-access
version: v8
spec:
  allow:
    kubernetes_labels:
      "*": "*"
    kubernetes_resources:
      # dev 네임스페이스의 모든 리소스에 대한 접근을 부여합니다.
      # v8에서는 네임스페이스가 설정된 경우 "*"에 클러스터 범위 리소스가 포함되지 않습니다.
      - kind: "*"
        api_group: "*"
        name: "*"
        namespace: dev
        verbs: ["*"]
      # 모든 클러스터 범위 리소스에 대한 접근을 부여합니다.
      - kind: "*"
        api_group: "*"
        name: "*"
        namespace: ""  # 빈 네임스페이스는 클러스터 범위 리소스만 일치함을 의미합니다.
        verbs: ["*"]
  deny:
    kubernetes_resources:
      - kind: clusterroles  # v8은 복수형을 사용합니다.
        api_group: "*"
        name: "*"
    # ...
모든 항목에 대한 전체 접근#
kind: role
metadata:
  name: kube-access
version: v7
spec:
  allow:
    kubernetes_labels:
      "*": "*"
    kubernetes_resources:
      - kind: "*"
        name: "*"
        namespace: "*"
        verbs: ["*"]
    # ...
kind: role
metadata:
  name: kube-access
version: v8
spec:
  allow:
    kubernetes_labels:
      "*": "*"
    kubernetes_resources:
      - kind: "*"
        api_group: "*"
        name: "*"
        namespace: "*"  # 와일드카드 '*'는 네임스페이스가 지정된 리소스와 클러스터 범위 리소스 모두와 일치합니다.
        verbs: ["*"]
    # ...

Kubernetes 서비스가 Teleport 역할을 평가하는 방식#

Teleport 사용자가 Kubernetes 클러스터의 API 서버에 요청을 보내면, Teleport Kubernetes 서비스는 요청을 가로채고 사용자의 인가를 검사합니다. 사용자가 특정 리소스를 볼 권한이 없는 경우 Kubernetes 서비스는 요청을 거부합니다. 사용자가 요청을 수행할 권한이 있는 경우, Kubernetes 서비스는 요청을 수정하여 적절한 API 서버로 전달합니다.

사용자 요청 인가#

Teleport Kubernetes 서비스는 요청을 받으면 사용자 역할 내의 두 필드를 평가합니다. 이러한 필드 중 하나라도 사용자가 요청을 수행하도록 허용하지 않으면, Kubernetes 서비스는 사용자에게 오류를 반환합니다:

kubernetes_labels#

Teleport Kubernetes 서비스는 파드가 실행 중인 클러스터에 사용자의 kubernetes_labels 구성과 일치하는 라벨이 있는 경우에만 파드에 대한 접근을 허용합니다.

kubernetes_resources#

Kubernetes API 서버 내의 일부 리소스 URI에는 특정 리소스의 이름이 포함됩니다.

예를 들어, 사용자가 kubectl exec를 실행하여 development 네임스페이스의 webapp 파드에 대해 명령을 실행하면, kubectl은 대상 클러스터의 API 서버에 다음 경로로 요청을 보냅니다:

"/api/v1/namespaces/development/pods/webapp/exec"

Kubernetes API 서버에 대한 요청의 URL 경로 내에 Kubernetes 파드가 있는 경우, Teleport Kubernetes 서비스는 사용자가 해당 파드에 접근할 권한이 있는지 확인합니다.

위 예시에서 Kubernetes 서비스는 사용자가 development 네임스페이스의 webapp 파드에 접근할 권한이 있는지 확인하고, 없으면 요청을 거부합니다.

사용자 요청 전달#

Teleport Kubernetes 서비스가 사용자가 Kubernetes 클러스터와 (해당하는 경우) 특정 리소스에 대해 요청을 수행할 권한이 있다고 인가하면, 상위 API 서버에 대한 요청을 조립합니다. 사용자 역할의 kubernetes_groupskubernetes_users 필드(앞서 설명한 이 필드에 대한 설명 참조)를 기반으로 요청에 임퍼소네이션 헤더를 추가합니다.

Teleport Kubernetes 서비스는 Teleport 사용자의 kubernetes_groupskubernetes_users 필드에 나열된 RBAC 프린시펄을 통해 상위 API 서버에 접근하므로, 이러한 필드에 지정하는 프린시펄은 사용자의 kubernetes_resources 필드에 나열된 리소스에 대한 접근 권한을 가지고 있어야 합니다. 그렇지 않으면 Kubernetes 서비스는 부적절한 인가로 요청을 상위 API 서버에 전달하게 되고, API 서버는 요청을 거부합니다.

여러 역할#

Kubernetes 서비스가 여러 역할을 평가하는 방식#

Teleport Kubernetes 서비스는 사용자의 Kubernetes API 서버에 대한 요청을 평가하기 전에 사용자의 각 역할을 확인합니다. 한 역할의 spec.allow.kubernetes_labels 또는 spec.allow.kubernetes_resources 조건이 사용자의 요청과 일치하지 않으면, Kubernetes 서비스는 다음 역할을 확인하며, 이런 식으로 계속됩니다.

Kubernetes 서비스가 클러스터의 모든 라벨과 요청의 리소스와 일치하는 spec.allow 조건을 가진 역할을 찾으면, 해당 역할의 allow.kubernetes_groupsallow.kubernetes_users 필드를 조회합니다. 이후 임퍼소네이션 헤더를 작성하는 데 사용할 RBAC 프린시펄 목록에 이러한 값을 추가합니다.

다음으로 Kubernetes 서비스는 사용자의 각 역할에서 spec.deny 조건을 확인합니다. 한 역할의 spec.deny.kubernetes_labels 또는 spec.deny.kubernetes_resources 필드가 사용자의 요청과 일치하면, Kubernetes 서비스는 해당 역할의 spec.deny.kubernetes_groupsspec.deny.kubernetes_users 필드를 조회합니다. 이전에 생성한 사용자와 그룹 목록에서 이러한 값을 각각 제거하여, 사용자가 이러한 RBAC 프린시펄에 접근하지 못하도록 거부합니다.

예시#

사용자에게 다음 세 가지 역할이 할당되어 있다고 가정해 보겠습니다:

kind: role
metadata:
  name: allow-dev-us-east-2
version: v7
spec:
  allow:
    kubernetes_labels:
      "region": "us-east-2"
    kubernetes_resources:
      - kind: pod
        namespace: "development"
        name: "redis-*"
      - kind: pod
        namespace: "development"
        name: "nginx-*"
    kubernetes_groups:
      - dev-viewers # 사용자가 development 네임스페이스에서 파드를 볼 수 있도록 허용합니다
---
kind: role
metadata:
  name: allow-exec
version: v7
spec:
  allow:
    kubernetes_labels:
        "*": "*"
    kubernetes_resources:
      - kind: pod
        namespace: "*"
        name: "*"
    kubernetes_groups:
      - executors # 사용자가 모든 파드에 대해 명령을 실행할 수 있도록 허용합니다
---
kind: role
metadata:
  name: deny-redis-exec
version: v7
spec:
  deny:
    kubernetes_resources:
      - kind: pod
        namespace: "*"
        name: "redis-*"
    kubernetes_groups:
      - executors

dev-viewers Kubernetes 그룹은 사용자가 development 네임스페이스의 파드를 볼 수 있도록 허용합니다. executors Kubernetes 그룹은 사용자가 모든 네임스페이스의 모든 파드에 대해 명령을 실행할 수 있도록 허용합니다.

이러한 역할을 가진 사용자가 development 네임스페이스에서 kubectl get pods/redis-1을 실행하고 클러스터에 region:us-east-2 라벨이 있는 경우, Kubernetes 서비스는 요청을 수락합니다. deny-redis-exec 역할이 redis-* 파드에 대해 executors 그룹을 거부하기 때문에, Kubernetes 서비스는 dev-viewers 그룹은 임퍼소네이트하지만 executors 그룹은 임퍼소네이트하지 않은 상태로 요청을 전달합니다.

그러나 동일한 사용자가 동일한 클러스터에 대해 development 네임스페이스에서 kubectl exec -it nginx /bin/bash를 실행하면, deny-redis-exec 역할의 deny 조건이 요청과 일치하지 않으므로 Kubernetes 서비스는 dev-viewersexecutors 그룹 모두에 대한 임퍼소네이션 헤더로 요청을 전달합니다.

리소스에 대한 접근을 점진적으로 활성화#

Teleport와 Kubernetes RBAC를 설계하여 제한된 Kubernetes 리소스 부분 집합에 대한 접근을 점진적으로 허용할 수 있습니다. 다시 말해, 사용자는 Kubernetes 클러스터의 광범위한 리소스에 제한된 접근 권한을 갖게 됩니다. 이러한 사용자의 부분 집합은 더 제한된 리소스 집합에 더 큰 접근 권한을 갖게 됩니다. 이러한 사용자의 부분 집합 중에서, 다른 리소스 집합에 대해 더 작은 그룹에 더 큰 접근 권한을 할당할 수 있으며, 이런 식으로 계속됩니다.

이를 위해 다음과 같은 여러 Teleport 역할을 정의합니다:

그런 다음 서로 다른 사용자에게 역할의 조합을 할당할 수 있습니다.

예를 들어, 다음 역할 조합은 사용자가 등록된 모든 Kubernetes 클러스터에서 모든 파드를 볼 수 있도록 허용하지만, nginx-* 파드에서만 kubectl exec 또는 kubectl logs를 실행할 수 있도록 합니다:

kind: role
metadata:
  name: kube-viewer
version: v7
spec:
  allow:
    kubernetes_labels:
      '*': '*'
    kubernetes_resources:
      - kind: pod
        namespace: "*"
        name: "*"
    kubernetes_groups:
    - viewer # 파드를 가져오고 목록을 조회할 수 있지만 명령 실행이나 로그 검색은 할 수 없습니다
---
kind: role
metadata:
  name: nginx-exec
version: v7
spec:
  allow:
    kubernetes_labels:
      '*': '*'
    kubernetes_resources:
      - kind: pod
        namespace: "*"
        name: "nginx-*"
    kubernetes_groups:
    - execAndLogs

이 경우, kube-viewer 역할은 사용자를 Kubernetes viewer 그룹에 매핑하여, 사용자가 파드를 가져오고 목록을 조회할 수 있지만 명령을 실행하거나 로그를 검색할 수는 없도록 합니다. nginx-exec 역할을 사용하면, 사용자는 명령을 실행하고 로그를 검색할 수 있는 execAndLogs 그룹에 접근할 수 있지만, nginx 파드에서만 가능합니다.

이 설정에서는 Teleport 사용자의 요구 사항에 따라 kube-viewer 역할을 파드의 부분 집합에 대한 상승된 접근 권한을 부여하는 다른 역할과 결합할 수도 있습니다.

보안 고려 사항: 리소스 네임스페이스 제한#

Teleport 사용자가 예를 들어 kubectl get pods로 파드 목록 조회 요청을 보내면, Teleport Kubernetes 서비스는 다음을 수행합니다:

의도치 않게 리소스가 유출되는 것을 방지하려면, Kubernetes RBAC의 네임스페이스 제한이 Teleport에 설정한 제한과 일치하는지 확인해야 합니다.

예를 들어, 사용자가 어떤 네임스페이스의 어떤 파드에도 접근을 허용하는 Teleport 역할을 가지고 있고, 해당 사용자를 default-pod-viewer Kubernetes 그룹에 매핑한다고 가정해 보겠습니다. 이 그룹은 default 네임스페이스의 파드만 볼 수 있습니다:

kind: role
metadata:
  name: kube-access-1
version: v7
spec:
  allow:
    kubernetes_groups:
      - default-pod-viewer
    kubernetes_resources:
      - kind: pod
        namespace: "*"
        name: "*"
    # ...

사용자는 두 번째 Teleport 역할을 가지고 있으며, 이는 사용자를 system:masters Kubernetes 그룹(모든 네임스페이스의 모든 파드에 접근 가능)에 매핑하고, default 네임스페이스의 webapp 파드에만 접근 권한을 부여합니다:

metadata:
  name: kube-access-2
version: v7
spec:
  allow:
    kubernetes_groups:
      - system:masters
    kubernetes_resources:
      - kind: pod
        namespace: "default"
        name: "webapp"
    # ...

kube-access-2 역할이 사용자를 system:masters에 매핑하므로, Kubernetes 서비스가 이 사용자로부터 요청을 전달할 때 요청의 임퍼소네이션 헤더에 system:masters 그룹을 추가하여 Kubernetes 클러스터에서 모든 파드를 가져옵니다.

그러나 사용자는 모든 네임스페이스의 모든 파드에 대한 접근을 허용하는 역할(kube-access-1)도 가지고 있으므로, Kubernetes 서비스는 API 서버에 대한 첫 번째 요청을 통해 가져온 파드를 필터링하지 않습니다.

즉, Kubernetes 서비스는 Teleport가 default 네임스페이스의 webapp 파드에만 접근을 허용하기 위해 사용자를 system:masters 그룹에 매핑했다는 것을 알 방법이 없습니다.

Teleport RBAC에 네임스페이스 제한이 있는 경우, Teleport 사용자에게 매핑하는 Kubernetes RBAC 리소스에도 동일한 네임스페이스 제한이 있는지 확인해야 합니다.

예를 들어, 다음과 같은 권한을 갖도록 kube-access-1 역할을 다시 작성하여 사용자를 default 네임스페이스의 파드로 제한해야 합니다:

kind: role
metadata:
  name: kube-access-1
version: v7
spec:
  allow:
    kubernetes_groups:
      - default-pod-viewer
    kubernetes_resources:
      - kind: pod
        namespace: "default"
        name: "*"
    # ...