InfoGrab 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#

Teleport에 Kubernetes 클러스터를 등록할 때 레이블을 추가할 수 있습니다. 역할의 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-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 서비스는 impersonation 헤더를 사용하여 하나의 Kubernetes 사용자와 0개 이상의 Kubernetes 그룹으로 API 서버에 요청을 보냅니다.

가장

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는 이를 무시합니다.

다음은 그룹 cluster-viewer-group과 사용자 cluster-viewer-user에 기본 제공 view ClusterRole을 할당하는 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 사용자, 그룹 및 서비스 계정을 가장하는 방법#

최종 사용자가 가장할 사용자나 서비스 계정 및 그룹을 지정하는 두 가지 방법이 있습니다:

수동으로#

사용자가 tsh kube login을 실행하여 Kubernetes 클러스터에 인증할 때, --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

일반적으로 이러한 리소스를 수동으로 정의할 필요가 없습니다. Teleport로 Kubernetes 클러스터를 등록하는 수동 방법자동 방법에는 클러스터에 대한 접근을 허용하기 위해 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 사용자에 대해 개별적으로 Kubernetes 그룹 및 사용자를 지정할 수 있습니다. 이를 위해 Teleport 역할에 템플릿 변수를 추가할 수 있으며, Teleport Auth 서비스는 각 인증 사용자의 정보로 이를 채웁니다.

Teleport 역할에서 템플릿 변수 확장이 작동하는 방법에 대한 자세한 내용은 접근 제어 참조를 참조하세요.

SSO(Single Sign-On) 공급자 트레이트#

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) 구성#

특정 Kubernetes 리소스에 대한 즉시 접근을 활성화하기 위해 Teleport 역할을 설정하는 경우, Kubernetes에 대한 접근 권한이 없는 주체를 가진 역할의 kubernetes_groupskubernetes_users를 설정해야 합니다.

Teleport가 제한할 수 있는 Kubernetes 리소스 종류를 제외한 모든 Kubernetes 리소스에 접근할 수 있기 때문입니다.

이는 사용자가 Kubernetes Pod에 대한 접근을 요청하고 요청이 승인되면, 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 필드에 관계없이 클러스터 전체 리소스를 포함했던 이전 역할 버전과 다릅니다.

와일드카드 *를 사용하면 클러스터 전체 리소스를 포함한 모든 리소스와 일치합니다(kind/api_group 기반). 빈 문자열 ""은 클러스터 전체 리소스만 일치시킵니다. ^.+$와 같은 다른 값은 네임스페이스 리소스만 일치시키고 클러스터 전체 리소스는 제외합니다.

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

Tip

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

역할 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 필드가 적용되므로, 업그레이드 시 특히 거부 측에서 리소스를 조정해야 할 수 있습니다.

Warning

namespace 종류는 네임스페이스 리소스와 그 안의 모든 리소스를 포함합니다. 이 동작은 리소스 자체만 포함하는 이후 역할 버전과 다르므로, 업그레이드 시 특히 거부 측에서 리소스를 조정해야 할 수 있습니다.

종류 접근 권한
* namespace 필드에 관계없이 클러스터 전체 리소스를 포함한 모든 리소스
pod Pod
secret Secrets
configmap ConfigMaps
namespace 네임스페이스 및 그 안의 모든 리소스.
service Services
serviceaccount ServiceAccounts
kube_node Nodes
persistentvolume PersistentVolumes
persistentvolumeclaim PersistentVolumeClaims
deployment Deployments
replicaset ReplicaSets
statefulset StatefulSets
daemonset DaemonSets
clusterrole ClusterRoles
kube_role Roles
clusterrolebinding ClusterRoleBindings
rolebinding RoleBindings
cronjob CronJobs
job Jobs
certificatesigningrequest CertificateSigningRequests
ingress Ingresses

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

Tip

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

역할 V6#

Tip

역할 V6은 kubernetes_resources 필드에 대한 지원을 도입했지만, pod 종류의 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 이름의 Pod와 일치합니다. kubernetes_labels와 마찬가지로, 값이 ^로 시작하고 $로 끝나면, Kubernetes 서비스는 Go의 re2 구문을 사용하여 정규 표현식으로 처리합니다(re2 README 참조).

Tip

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

예시#

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: ["*"]
    # ...
clusterroles를 제외한 dev 네임스페이스 및 모든 클러스터 전체 리소스에 대한 전체 접근#

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

kind: role
metadata:
  name: kube-access
version: v7
spec:
  allow:
    kubernetes_labels:
      "*": "*"
    kubernetes_resources:
      # v7에서 "*"는 namespace에 관계없이 클러스터 전체 리소스를 포함합니다.
      - 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에서 "*"는 namespace가 설정된 경우 클러스터 전체 리소스를 포함하지 않습니다.
      - 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 서비스는 Pod가 실행되는 클러스터에 사용자의 kubernetes_labels 구성과 일치하는 레이블이 있는 경우에만 사용자의 Pod 접근을 허용합니다.

kubernetes_resources#

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

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

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

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

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

사용자 요청 전달#

Teleport Kubernetes 서비스가 사용자가 Kubernetes 클러스터와 (해당하는 경우) 특정 리소스에 대한 요청을 수행할 권한이 있음을 승인하면, 업스트림 API 서버에 대한 요청을 조합합니다. 사용자 역할의 kubernetes_groupskubernetes_users 필드를 기반으로 요청에 가장 헤더를 추가합니다 (이러한 필드에 대한 이전 토론 참조).

Teleport Kubernetes 서비스는 Teleport 사용자의 kubernetes_groupskubernetes_users 필드에 나열된 RBAC 주체를 통해 업스트림 API 서버에 접근하므로, 이 필드에 지정하는 주체는 사용자의 kubernetes_resources 필드에 나열된 리소스에 접근할 수 있어야 합니다. 그렇지 않으면, Kubernetes 서비스는 부적절한 권한으로 업스트림 API 서버에 요청을 전달하고, API 서버는 요청을 거부합니다.

여러 역할#

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

Kubernetes API 서버에 대한 사용자 요청을 평가하기 전에, Teleport Kubernetes 서비스는 사용자의 각 역할을 확인합니다. 하나의 역할의 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 네임스페이스의 Pod를 볼 수 있도록 허용
---
kind: role
metadata:
  name: allow-exec
  version: v7
spec:
  allow:
    kubernetes_labels:
      - "*": "*"
    kubernetes_resources:
      - kind: pod
        namespace: "*"
        name: "*"
    kubernetes_groups:
      - executors # 사용자가 모든 Pod에 대해 명령어를 실행할 수 있도록 허용
---
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 네임스페이스의 Pod를 볼 수 있게 합니다. executors Kubernetes 그룹은 사용자가 모든 네임스페이스의 모든 Pod에 대해 명령어를 실행할 수 있게 합니다.

이러한 역할을 가진 사용자가 development 네임스페이스에서 kubectl get pods/redis-1을 실행하고 클러스터에 region:us-east-2 레이블이 있으면, Kubernetes 서비스는 요청을 수락합니다. deny-redis-exec 역할이 redis-* Pod에 대해 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 클러스터의 모든 Pod를 볼 수 있게 하지만 nginx-* Pod에서만 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 # Pod를 가져오고 목록을 조회할 수 있지만 명령어를 실행하거나 로그를 검색할 수 없음
---
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 그룹에 매핑하여 사용자가 Pod를 가져오고 목록을 조회하지만 명령어를 실행하고 로그를 검색할 수 없게 합니다. nginx-exec 역할을 통해, 사용자는 execAndLogs 그룹에 접근할 수 있어 명령어를 실행하고 로그를 검색할 수 있지만 nginx Pod에서만 가능합니다.

이 설정에서, Teleport 사용자의 요구 사항에 따라 Pod 하위 집합에 대한 높은 수준의 접근 권한을 부여하는 다른 역할과 kube-viewer 역할을 결합할 수도 있습니다.

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

Teleport 사용자가 kubectl get pods와 같이 Pod를 나열하는 요청을 보내면, Teleport Kubernetes 서비스는 다음을 수행합니다:

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

예를 들어, 사용자에게 모든 네임스페이스의 임의 Pod에 접근 권한을 부여하고 사용자를 default-pod-viewer Kubernetes 그룹에 매핑하는 Teleport 역할이 있다고 가정합니다. 이 그룹은 default 네임스페이스의 Pod만 볼 수 있습니다:

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

사용자에게는 사용자를 system:masters Kubernetes 그룹(모든 네임스페이스의 임의 Pod에 접근할 수 있음)에 매핑하고 default 네임스페이스의 webapp Pod에만 접근 권한을 부여하는 두 번째 Teleport 역할이 있습니다:

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 클러스터에서 모든 Pod를 가져옵니다.

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

즉, Kubernetes 서비스는 webapp Pod에만 접근 권한을 부여하기 위해 Teleport가 사용자를 system:masters 그룹에 매핑했다는 것을 알 방법이 없습니다.

Teleport RBAC에 네임스페이스 제한이 있는 경우, 매핑된 Teleport 사용자의 Kubernetes RBAC 리소스에도 동일한 네임스페이스 제한이 있어야 합니다.

예를 들어, 사용자를 default 네임스페이스의 Pod로 제한하기 위해 다음 권한을 가지도록 kube-access-1 역할을 다시 작성해야 합니다:

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 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#

Teleport에 Kubernetes 클러스터를 등록할 때 레이블을 추가할 수 있습니다. 역할의 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-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 서비스는 impersonation 헤더를 사용하여 하나의 Kubernetes 사용자와 0개 이상의 Kubernetes 그룹으로 API 서버에 요청을 보냅니다.

가장

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는 이를 무시합니다.

다음은 그룹 cluster-viewer-group과 사용자 cluster-viewer-user에 기본 제공 view ClusterRole을 할당하는 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 사용자, 그룹 및 서비스 계정을 가장하는 방법#

최종 사용자가 가장할 사용자나 서비스 계정 및 그룹을 지정하는 두 가지 방법이 있습니다:

수동으로#

사용자가 tsh kube login을 실행하여 Kubernetes 클러스터에 인증할 때, --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

일반적으로 이러한 리소스를 수동으로 정의할 필요가 없습니다. Teleport로 Kubernetes 클러스터를 등록하는 수동 방법자동 방법에는 클러스터에 대한 접근을 허용하기 위해 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 사용자에 대해 개별적으로 Kubernetes 그룹 및 사용자를 지정할 수 있습니다. 이를 위해 Teleport 역할에 템플릿 변수를 추가할 수 있으며, Teleport Auth 서비스는 각 인증 사용자의 정보로 이를 채웁니다.

Teleport 역할에서 템플릿 변수 확장이 작동하는 방법에 대한 자세한 내용은 접근 제어 참조를 참조하세요.

SSO(Single Sign-On) 공급자 트레이트#

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) 구성#

특정 Kubernetes 리소스에 대한 즉시 접근을 활성화하기 위해 Teleport 역할을 설정하는 경우, Kubernetes에 대한 접근 권한이 없는 주체를 가진 역할의 kubernetes_groupskubernetes_users를 설정해야 합니다.

Teleport가 제한할 수 있는 Kubernetes 리소스 종류를 제외한 모든 Kubernetes 리소스에 접근할 수 있기 때문입니다.

이는 사용자가 Kubernetes Pod에 대한 접근을 요청하고 요청이 승인되면, 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

와일드카드 *를 사용하면 클러스터 전체 리소스를 포함한 모든 리소스와 일치합니다(kind/api_group 기반). 빈 문자열 ""은 클러스터 전체 리소스만 일치시킵니다. ^.+$와 같은 다른 값은 네임스페이스 리소스만 일치시키고 클러스터 전체 리소스는 제외합니다.

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

Tip

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

역할 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 필드가 적용되므로, 업그레이드 시 특히 거부 측에서 리소스를 조정해야 할 수 있습니다.

Warning

namespace 종류는 네임스페이스 리소스와 그 안의 모든 리소스를 포함합니다. 이 동작은 리소스 자체만 포함하는 이후 역할 버전과 다르므로, 업그레이드 시 특히 거부 측에서 리소스를 조정해야 할 수 있습니다.

종류 접근 권한
* namespace 필드에 관계없이 클러스터 전체 리소스를 포함한 모든 리소스
pod Pod
secret Secrets
configmap ConfigMaps
namespace 네임스페이스 및 그 안의 모든 리소스.
service Services
serviceaccount ServiceAccounts
kube_node Nodes
persistentvolume PersistentVolumes
persistentvolumeclaim PersistentVolumeClaims
deployment Deployments
replicaset ReplicaSets
statefulset StatefulSets
daemonset DaemonSets
clusterrole ClusterRoles
kube_role Roles
clusterrolebinding ClusterRoleBindings
rolebinding RoleBindings
cronjob CronJobs
job Jobs
certificatesigningrequest CertificateSigningRequests
ingress Ingresses

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

Tip

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

역할 V6#

Tip

역할 V6은 kubernetes_resources 필드에 대한 지원을 도입했지만, pod 종류의 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 이름의 Pod와 일치합니다. kubernetes_labels와 마찬가지로, 값이 ^로 시작하고 $로 끝나면, Kubernetes 서비스는 Go의 re2 구문을 사용하여 정규 표현식으로 처리합니다(re2 README 참조).

Tip

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

예시#

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: ["*"]
    # ...
clusterroles를 제외한 dev 네임스페이스 및 모든 클러스터 전체 리소스에 대한 전체 접근#

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

kind: role
metadata:
  name: kube-access
version: v7
spec:
  allow:
    kubernetes_labels:
      "*": "*"
    kubernetes_resources:
      # v7에서 "*"는 namespace에 관계없이 클러스터 전체 리소스를 포함합니다.
      - 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에서 "*"는 namespace가 설정된 경우 클러스터 전체 리소스를 포함하지 않습니다.
      - 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 서비스는 Pod가 실행되는 클러스터에 사용자의 kubernetes_labels 구성과 일치하는 레이블이 있는 경우에만 사용자의 Pod 접근을 허용합니다.

kubernetes_resources#

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

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

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

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

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

사용자 요청 전달#

Teleport Kubernetes 서비스가 사용자가 Kubernetes 클러스터와 (해당하는 경우) 특정 리소스에 대한 요청을 수행할 권한이 있음을 승인하면, 업스트림 API 서버에 대한 요청을 조합합니다. 사용자 역할의 kubernetes_groupskubernetes_users 필드를 기반으로 요청에 가장 헤더를 추가합니다 (이러한 필드에 대한 이전 토론 참조).

Teleport Kubernetes 서비스는 Teleport 사용자의 kubernetes_groupskubernetes_users 필드에 나열된 RBAC 주체를 통해 업스트림 API 서버에 접근하므로, 이 필드에 지정하는 주체는 사용자의 kubernetes_resources 필드에 나열된 리소스에 접근할 수 있어야 합니다. 그렇지 않으면, Kubernetes 서비스는 부적절한 권한으로 업스트림 API 서버에 요청을 전달하고, API 서버는 요청을 거부합니다.

여러 역할#

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

Kubernetes API 서버에 대한 사용자 요청을 평가하기 전에, Teleport Kubernetes 서비스는 사용자의 각 역할을 확인합니다. 하나의 역할의 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 네임스페이스의 Pod를 볼 수 있도록 허용
---
kind: role
metadata:
  name: allow-exec
  version: v7
spec:
  allow:
    kubernetes_labels:
      - "*": "*"
    kubernetes_resources:
      - kind: pod
        namespace: "*"
        name: "*"
    kubernetes_groups:
      - executors # 사용자가 모든 Pod에 대해 명령어를 실행할 수 있도록 허용
---
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 네임스페이스의 Pod를 볼 수 있게 합니다. executors Kubernetes 그룹은 사용자가 모든 네임스페이스의 모든 Pod에 대해 명령어를 실행할 수 있게 합니다.

이러한 역할을 가진 사용자가 development 네임스페이스에서 kubectl get pods/redis-1을 실행하고 클러스터에 region:us-east-2 레이블이 있으면, Kubernetes 서비스는 요청을 수락합니다. deny-redis-exec 역할이 redis-* Pod에 대해 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 클러스터의 모든 Pod를 볼 수 있게 하지만 nginx-* Pod에서만 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 # Pod를 가져오고 목록을 조회할 수 있지만 명령어를 실행하거나 로그를 검색할 수 없음
---
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 그룹에 매핑하여 사용자가 Pod를 가져오고 목록을 조회하지만 명령어를 실행하고 로그를 검색할 수 없게 합니다. nginx-exec 역할을 통해, 사용자는 execAndLogs 그룹에 접근할 수 있어 명령어를 실행하고 로그를 검색할 수 있지만 nginx Pod에서만 가능합니다.

이 설정에서, Teleport 사용자의 요구 사항에 따라 Pod 하위 집합에 대한 높은 수준의 접근 권한을 부여하는 다른 역할과 kube-viewer 역할을 결합할 수도 있습니다.

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

Teleport 사용자가 kubectl get pods와 같이 Pod를 나열하는 요청을 보내면, Teleport Kubernetes 서비스는 다음을 수행합니다:

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

예를 들어, 사용자에게 모든 네임스페이스의 임의 Pod에 접근 권한을 부여하고 사용자를 default-pod-viewer Kubernetes 그룹에 매핑하는 Teleport 역할이 있다고 가정합니다. 이 그룹은 default 네임스페이스의 Pod만 볼 수 있습니다:

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

사용자에게는 사용자를 system:masters Kubernetes 그룹(모든 네임스페이스의 임의 Pod에 접근할 수 있음)에 매핑하고 default 네임스페이스의 webapp Pod에만 접근 권한을 부여하는 두 번째 Teleport 역할이 있습니다:

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 클러스터에서 모든 Pod를 가져옵니다.

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

즉, Kubernetes 서비스는 webapp Pod에만 접근 권한을 부여하기 위해 Teleport가 사용자를 system:masters 그룹에 매핑했다는 것을 알 방법이 없습니다.

Teleport RBAC에 네임스페이스 제한이 있는 경우, 매핑된 Teleport 사용자의 Kubernetes RBAC 리소스에도 동일한 네임스페이스 제한이 있어야 합니다.

예를 들어, 사용자를 default 네임스페이스의 Pod로 제한하기 위해 다음 권한을 가지도록 kube-access-1 역할을 다시 작성해야 합니다:

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