RBAC 를 사용한 안전한 Kubernetes 액세스

KubernetesBeginner
지금 연습하기

소개

Kubernetes 인증은 요청한 주체를 식별하고, 인가는 해당 주체가 수행할 수 있는 작업을 결정합니다. RBAC 는 API 리소스에 대한 동작을 권한으로 표현하고, 이를 사용자, 그룹 또는 ServiceAccount 에 연결합니다.

이 실습에서는 네임스페이스 범위의 읽기 전용 주체를 만들고, 해당 주체의 ID 를 권한에 연결한 다음, 가장을 통해 허용되는 작업과 거부되는 작업의 경계를 모두 확인합니다.

RBAC 는 다음 세 가지 질문으로 이해하면 쉽습니다. 누구인가? (ServiceAccount), 무엇을 할 수 있는가? (Role), 그 권한을 누가 받는가? (RoleBinding). 이 객체 중 하나나 두 개만 만든다고 해서 인가 경로가 완성되는 것은 아닙니다.

ServiceAccount ID 만들기

이 단계에서는 애플리케이션 구성 요소를 위한 네임스페이스 범위의 ServiceAccount 를 만듭니다.

ServiceAccount 는 워크로드와 자동화를 위해 사용하는 Kubernetes API ID 입니다. 컨테이너 내부의 Linux 사용자는 아닙니다. 이 예제에 전용 ID 를 사용하면 네임스페이스의 default ServiceAccount 권한을 무심코 상속하는 일을 방지할 수 있습니다.

cd /home/labex/project/rbac-access
kubectl create serviceaccount inventory-reader -n practice-rbac
kubectl get serviceaccount inventory-reader -n practice-rbac -o yaml

이 ID 의 전체 이름은 system:serviceaccount:practice-rbac:inventory-reader입니다. ID 만 만든다고 해서 애플리케이션 권한이 부여되지는 않습니다.

YAML 출력의 메타데이터에서 네임스페이스와 이름을 확인할 수 있습니다. 장기간 유지되는 토큰 Secret 이 자동으로 생성될 것이라고 기대하지 마세요. 최신 Kubernetes 프로젝트에서는 필요할 때 단기 토큰을 Pod 에 주입합니다.

반환된 객체에는 지정된 이름과 네임스페이스가 포함되지만, 자동으로 생성된 토큰 Secret 은 없습니다.

kind: ServiceAccount
metadata:
  name: inventory-reader
  namespace: practice-rbac

네임스페이스 범위 권한 정의하기

이 단계에서는 practice-rbac 네임스페이스에서만 Pod 와 ConfigMap 을 읽을 수 있도록 허용하는 Role 을 만듭니다.

각 규칙은 API 그룹, 리소스, 동작을 조합합니다. Pod 와 ConfigMap 같은 핵심 리소스의 경우 apiGroups: [""]처럼 빈 문자열을 사용합니다. get, list, watch 동작은 각각 개별 객체 읽기, 목록 읽기, 변경 사항 감시를 의미합니다.

cd /home/labex/project/rbac-access
cat <<'EOF' > inventory-role.yaml
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata: {name: inventory-reader, namespace: practice-rbac}
rules:
  - apiGroups: [""]
    resources: [pods, configmaps]
    verbs: [get, list, watch]
EOF

Role 을 적용하고 자세히 확인합니다. describe 명령은 정책 규칙을 원시 YAML 보다 검토하기 쉬운 표 형식으로 보여 줍니다.

kubectl apply -f inventory-role.yaml
kubectl describe role inventory-reader -n practice-rbac

빈 API 그룹은 핵심 리소스를 선택합니다. Role 은 자신의 네임스페이스 외부에 대한 접근 권한을 부여하지 않습니다.

또한 정의되지 않은 권한도 확인해 보세요. create, update, patch, delete가 없습니다. 최소 권한 원칙은 부여된 권한뿐 아니라 의도적으로 제외된 권한으로도 결정됩니다.

Resources   Non-Resource URLs  Resource Names  Verbs
---------   -----------------  --------------  -----
configmaps  []                 []              [get list watch]
pods        []                 []              [get list watch]

이 표는 하나의 YAML 규칙을 리소스별 한 행으로 펼쳐 보여 줍니다. 두 행 모두 동일한 세 가지 읽기 전용 동작을 갖습니다.

Role 을 ID 에 연결하기

이 단계에서는 RoleBinding 을 사용하여 Role 을 ServiceAccount 에 연결합니다.

두 객체가 이미 존재하므로 명령을 간결하게 작성할 수 있습니다. --role은 권한의 출처를 지정하고, --serviceaccount는 namespace:name 형식으로 대상 주체를 식별합니다.

cd /home/labex/project/rbac-access
kubectl create rolebinding inventory-reader -n practice-rbac --role=inventory-reader --serviceaccount=practice-rbac:inventory-reader
kubectl get rolebinding inventory-reader -n practice-rbac -o yaml

roleRef는 권한을 지정하고, subjects는 해당 권한을 받을 ID 를 지정합니다. 여기서는 둘 다 네임스페이스 범위로 유지됩니다.

이름이 같은 Role 과 ServiceAccount 라도 이 바인딩이 생성되기 전까지는 서로 관련이 없습니다. 이름은 사람이 이해하기 위한 식별자일 뿐이며, 실제 인가 연결은 RoleBinding 이 담당합니다.

YAML 에서 roleRef.name: inventory-reader가 ServiceAccount 종류의 주체, 이름 inventory-reader, 네임스페이스 practice-rbac으로 연결되는 흐름을 확인하세요.

허용된 작업과 거부된 작업 테스트하기

이 단계에서는 --as 옵션과 함께 kubectl auth can-i를 사용하여 ServiceAccount 를 가장합니다.

인가를 테스트할 때는 긍정적인 사례와 부정적인 사례를 모두 확인해야 합니다. yes는 필요한 작업을 수행할 수 있음을 증명하고, no는 파괴적인 작업이나 다른 네임스페이스에 대한 접근 권한이 실수로 부여되지 않았음을 증명합니다.

cd /home/labex/project/rbac-access
IDENTITY=system:serviceaccount:practice-rbac:inventory-reader
kubectl auth can-i list pods -n practice-rbac --as="$IDENTITY"
kubectl auth can-i get configmaps -n practice-rbac --as="$IDENTITY"
kubectl auth can-i delete pods -n practice-rbac --as="$IDENTITY" || true
kubectl auth can-i list pods -n default --as="$IDENTITY" || true

처음 두 결과는 yes여야 하며, 삭제와 다른 네임스페이스의 목록 조회 결과는 no여야 합니다. 가장을 사용하면 토큰을 노출하거나 생성하지 않고도 인가를 테스트할 수 있습니다.

kubectl auth can-i는 no라는 결과와 함께 셸에서 0 이 아닌 상태 코드를 반환합니다. 뒤의 두 || true는 의도적으로 거부되는 테스트가 다음 단계로 계속 진행되도록 할 뿐이며, 인가 결정 자체를 바꾸지는 않습니다.

yes
yes
no
no

이를 필요한 두 가지 작업과 보호되는 두 가지 경계로 해석하세요. yes 결과만 포함된 테스트로는 최소 권한 원칙을 입증할 수 없습니다.

현재 실습 사용자는 테스트를 위해 이 ServiceAccount 를 가장할 수 있습니다. --as는 해당 명령에서 API 서버가 평가하는 ID 를 변경할 뿐이며, 셸 사용자나 kubectl 자격 증명을 변경하거나 영구적으로 전환하지는 않습니다.

요약

ServiceAccount 를 만들고, Role 을 사용해 네임스페이스 범위의 읽기 전용 권한을 정의했으며, RoleBinding 으로 해당 권한을 할당했습니다. 또한 가장을 사용하여 허용된 작업과 거부된 작업을 모두 확인했습니다.