💻Practice

AKS의 MDC 권장사항 완화 테스트

date
Jul 19, 2024
slug
aks-mdc-recommendation
type
Post
status
Public
progress
Done
category
💻Practice
tags
Azure
k8s
summary
Azure 네이티브 CSPM인 MDC(Microsoft Defender for Cloud)를 사용하여 보안적으로 미흡한 AKS 구성을 점검
thumbnail
updatedAt
Jun 26, 2025 04:39 AM
author

MDC(Microsoft Defender for Cloud)

Azure를 포함한 다중 클라우드 환경의 보안 취약 구성 점검(CSPM), 위협 탐지(CWPP) 및 DevOps 보안 점검 기능을 제공하는 Microsoft CNAPP(Cloud Native Application Protection Platform) 솔루션

CSPM

  • 기본 CSPM은 무료(규정준수에서도 조회 가능)
  • Defender CSPM(유료) 활성화할 경우 위험 경로 반영된 평가 결과 조회 가능.
    • 하단과 같은 페이지에서 리소스 수량을 파악할 수 있다. 참고로, 적용하고자 하는 리소스를 한정할 수는 없다. 구독 단위로 활성화하는 플랜이기 때문에, 구독에 있는 평가 대상 리소스가 모두 평가된다.
notion image
AKS 구성을 점검하기 위해, MDC에서 제공하는 CIS Azure Kubernetes Service(AKS) Benchamrk v1.5.0을 활용 하자.

❓CIS Benchmark

IT 환경 시스템, 소프트웨어, 네트워크, 인프라 등을 안전하게 구성하기 위한 모범 사례 모음집.
벤치마크 버전 별로 적용 가능한 대상 워크로드의 버전이 지정되어 있으니 확인이 필요하다(예: CIS Azure Kubernetes Service는 Kubernetes v1.27, v1.28, v1.29를 지원)
다음 링크에 회사 이메일로 폼 입력하면 벤치마크 pdf자료를 다운할 수 있는 링크를 수신할 수 있다.

세부 항목

1. Master (Control Plane) Components
2. Master (Control Plane) Configuration
2.1. Logging
  • 2.1.1. Enable audit Logs (Manual)
3. Worker Nodes
3.1. Worker Node Configuration Files
  • 3.1.1. Ensure that the kubeconfig file permissions are set to 644 or more restrictive (Automated)
  • 3.1.2. Ensure that the kubelet kubeconfig file ownership is set to root:root (Automated)
  • 3.1.3. Ensure that the azure.json file has permissions set to 644 or more restrictive (Automated)
  • 3.1.4. Ensure that the azure.json file ownership is set to root:root (Automated)
3.2. Kubelet
  • 3.2.1. Ensure that the --anonymous-auth argument is set to false (Automated)
  • 3.2.2. Ensure that the --authorization-mode argument is not set to AlwaysAllow (Automated)
  • 3.2.3. Ensure that the --client-ca-file argument is set as appropriate (Automated)
  • 3.2.4. Ensure that the --read-only-port is secured (Automated)
  • 3.2.5. Ensure that the --streaming-connection-idle-timeout argument is not set to 0 (Automated)
  • 3.2.6. Ensure that the --make-iptables-util-chains argument is set to true (Automated)
  • 3.2.7. Ensure that the --eventRecordQPS argument is set to 0 or a level which ensures appropriate event capture (Automated)
  • 3.2.8. Ensure that the --rotate-certificates argument is not set to false (Automated)
  • 3.2.9. Ensure that the RotateKubeletServerCertificate argument is set to true (Automated)
4. Policies
4.1. RBAC and Service Accounts
  • 4.1.1. Ensure that the cluster-admin role is only used where required (Automated)
  • 4.1.2. Minimize access to secrets (Automated)
  • 4.1.3. Minimize wildcard use in Roles and ClusterRoles (Automated)
  • 4.1.4. Minimize access to create pods (Automated)
  • 4.1.5. Ensure that default service accounts are not actively used (Automated)
  • 4.1.6. Ensure that Service Account Tokens are only mounted where necessary (Automated)
4.2. Pod Security Standards
  • 4.2.1. Minimize the admission of privileged containers (Automated)
  • 4.2.2. Minimize the admission of containers wishing to share the host process ID namespace (Automated)
  • 4.2.3. Minimize the admission of containers wishing to share the host IPC namespace (Automated)
  • 4.2.4. Minimize the admission of containers wishing to share the host network namespace (Automated)
  • 4.2.5. Minimize the admission of containers with allowPrivilegeEscalation (Automated)
4.3. Azure Policy / OPA
4.4. CNI Plugin
  • 4.4.1. Ensure latest CNI version is used (Automated)
  • 4.4.2. Ensure that all Namespaces have Network Policies defined (Automated)
4.5. Secrets Management
  • 4.5.1. Prefer using secrets as files over secrets as environment variables (Automated)
  • 4.5.2. Consider external secret storage (Manual)
4.6. General Policies
  • 4.6.1. Create administrative boundaries between resources using namespaces (Manual)
  • 4.6.2. Apply Security Context to Your Pods and Containers (Manual)
  • 4.6.3. The default namespace should not be used (Automated)
5. Managed Services
5.1. Image Registry and Image Scanning
  • 5.1.1. Ensure Image Vulnerability Scanning using Azure Defender image scanning or a third-party provider (Automated)
  • 5.1.2. Minimize user access to Azure Container Registry (ACR) (Manual)
  • 5.1.3. Minimize cluster access to read-only for Azure Container Registry (ACR) (Manual)
  • 5.1.4. Minimize Container Registries to only those approved (Manual)
5.2. Access and Identity Options for Azure Kubernetes Service (AKS)
  • 5.2.1. Prefer using dedicated AKS Service Accounts (Manual)
5.3. Key Management Service (KMS)
  • 5.3.1. Ensure Kubernetes Secrets are encrypted (Manual)
5.4. Cluster Networking
  • 5.4.1. Restrict Access to the Control Plane Endpoint (Automated)
  • 5.4.2. Ensure clusters are created with Private Endpoint Enabled and Public Access Disabled (Automated)
  • 5.4.3. Ensure clusters are created with Private Nodes (Automated)
  • 5.4.4. Ensure Network Policy is Enabled and set as appropriate (Automated)
  • 5.4.5. Encrypt traffic to HTTPS load balancers with TLS certificates (Manual)
5.5. Authentication and Authorization
  • 5.5.1. Manage Kubernetes RBAC users with Azure AD (Manual)
  • 5.5.2. Use Azure RBAC for Kubernetes Authorization (Manual)
AKS는 클라우드 관리형 서비스이기 때문에.. 사용자가 평가할 수 있는 항목, 수정할 수 있는 항목이 극히 제한적이긴 하다. 이 중 Control Plane 영역은 평가할 수 없다.
만약, 평가 항목을 직접 커스텀하고 싶다면, 방법은 있긴하나.. 쉽진 않다. 그 이유는 글 후반부에 언급할 예정.

MDC에서 CIS 벤치마크를 활성화

  1. Azure Portal의 클라우드용 Microsoft Defender > 관리 > 환경설정 에서 구독 목록 중 CIS를 활성화하고자 하는 구독 행의 오른쪽 … 을 클릭하면 나오는 ‘설정 편집’을 클릭한다.
    1. notion image
  1. 좌측 네비게이션 메뉴에서 설정 > 보안 정책을 클릭한 후, 표준에서 ‘AKS’를 검색하여 1.5.0 버전의 벤치마크을 찾는다.
    1. notion image
      우측 상태 토글을 클릭하여 활성화한다.
  1. 활성화 즉시 평가가 되진 않고, 모든 항목이 평가되기까지는 하루 정도는 기다려야 한다..
  1. 평가가 완료되면, 클라우드용 Microsoft Defender > 클라우드 보안 > 규정 준수에서 해당 벤치마크를 클릭하여 확인할 수 있다.
    1. notion image
각 규정 준수 컨트롤은 권장사항으로 구성되어있고, 각 권장사항의 스캔 주기는 상이하며 스캔 주기를 개인이 설정할 수 없다. 스캔 주기는 짧으면 30분, 체감상 길면 하루까지도 걸린다.
 
모든 규정 준수 컨트롤 확장을 클릭하여 항목별 권장사항을 확인하자.
notion image
파란색 글씨의 권장사항을 클릭하면 상세 페이지로 이동한다.
notion image
무엇에 대한 평가인지, 어떻게 완화하는지 간략한 가이드를 얻어 참고할 수 있고, 준수/비준수 리소스 목록도 확인 가능하다.
notion image
AKS 관련 권장사항은 현재(2025년 1월 중순 기준) 총 19개를 지원한다.
 

컴플라이언스 표준, 권장사항 커스텀

앞서 말했다시피, 직접 권장사항을 커스텀하여 커스텀한 컴플라이언스 표준을 만들 수도 있다.
notion image
  • 사용자 지정 표준
    • : 권장사항을 조합하여 커스텀 컴플라이언스 표준을 만들 수 있다.
      notion image
  • 사용자 지정 권장 사항
    • : Azure Graph 쿼리를 작성해서 생성할 수 있고, 사용자 지정 표준에만 등록 가능하다.
      notion image
그런데 기존 권장사항을 보면 Azure 내부에 이미 평가키가 정의되어 있고, 키 값을 검색하여 평가 결과를 조회하는 방식이다… 그렇기 때문에 말만 커스텀이지, 사용자가 커스텀할 수 있는 범위에 제약이 있다는 생각이 든다.
앞서 확인 했었던 ‘AKS 클러스터에서 클러스터 관리자 역할을 사용해서는 안 됩니다.’페이지 좌측 상단의 ‘쿼리 열기’ 클릭 시 확인 가능하다.
앞서 확인 했었던 ‘AKS 클러스터에서 클러스터 관리자 역할을 사용해서는 안 됩니다.’페이지 좌측 상단의 ‘쿼리 열기’ 클릭 시 확인 가능하다.
이렇게 보면 모든 권장사항은 그래프 쿼리로 작성되는거라고 생각할 수 있는데, 일부 권장사항은 Azure Policy로부터 가져온 것이다.
notion image
‘정책 정의 보기’ 클릭 시 원본 Azure Policy 정의 페이지로 넘어간다.
notion image
Azure Policy에는 MDC에서 볼 수 있는 권장사항 보다 더 많은 정책 정의가 존재한다.
확실히 세보진 않았지만, MDC에서 제공하는 AKS 권장사항 19개를 넘는다.
확실히 세보진 않았지만, MDC에서 제공하는 AKS 권장사항 19개를 넘는다.
사실 AKS에 Azure Policy로 평가하는 방법은, MDC의 CWP를 활성화 했을때 사용할 수 있다.
Azure Policy에 대해서는 이번 포스팅에서는 다루지 않을거고, 추후 별도로 관련 글을 쓸 예정..
정리하자면, 권장사항은 다음 2가지 방법으로 평가된다.
  1. Azure Graph 쿼리 실행
    1. 그런데 권장사항 별로 고유한 키가 있어, 키 값을 검색해서 결과를 확인하는 방식. 즉, 평가된 결과를 Azure Graph 쿼리로 검색하는 것 뿐.
  1. Azure Policy 정책 평가
 
이제 진짜 몇가지 권장사항을 참고하여 어떤 부분에서 위반되었는지 확인해보자.
(당장 조치하기에는 어려운 부분이 많아서 확인만 하는걸로~)

권장사항 완화

1️⃣ AKS(Azure Kubernetes Service) 클러스터에서 클러스터 관리자 역할을 사용해서는 안 됩니다.

클라우드용 Defender에서 AKS 클러스터에서 클러스터 관리자 역할이 사용되고 있음을 확인했습니다. 공격자가 클러스터의 모든 리소스를 완전히 제어할 위험이 있습니다. 클러스터의 모든 엔터티에서 클러스터 관리자 역할 바인딩을 제거하는 것이 좋습니다.
⇒ 기본적으로 cluster-role에 모든 권한이 부여되기 때문에, 사용을 권장하지 않는다.
notion image
  • 수정 방안
    • 1. Azure CLI에서 클러스터의 모든 클러스터 역할을 나열하려면 다음 명령을 실행합니다.
      kubectl get clusterrolebindings -o=custom-columns=NAME:.metadata.name,ROLE:.roleRef.name,SUBJECT:.subjects[*].name
      이건 파워쉘
      이건 파워쉘
      2. 주체가 Kubernetes 클러스터에 대한 관리자 액세스 권한이 필요하지 않으면 ClusterRoleBinding YAML 파일을 업데이트하여 역할 바인딩을 비관리자 역할로 다운그레이드 합니다.
      3. 다음 명령을 실행하여 설정을 적용합니다.
      kubectl apply -f [YAML FILE]
 

2️⃣ AKS(Azure Kubernetes Service) 클러스터에서 비밀 개체에 대한 액세스를 제한해야 합니다.

클라우드용 Defender에서 AKS 클러스터의 사용자 계정이 비밀 개체에 대한 get, list 또는 watch 권한이 있음을 확인했습니다. 이러한 사용자 계정에 액세스할 수 있는 공격자가 Kubernetes 클러스터 또는 외부 리소스에 대한 추가 액세스 권한을 얻을 수 있으므로 위험이 발생합니다. 이 액세스를 통해 비밀 개체에 포함된 데이터를 볼 수 있습니다. 클러스터의 비밀 개체에 대한 get, list 또는 watch 권한을 제거하는 것이 좋습니다.
⇒ Secret은 암호화되지 않고 base64 인코딩된 쿠버네티스 자원이기 때문에 패스워드, 키 값등을 디코딩하면 확인할 수 있다. 따라서 Secret에 접근할 수 있는 사용자는 제한해야 한다.
  • 수정 방안
    • AKS 클러스터에서 비밀 개체에 대한 권한을 제거합니다.
    • AKS 인증/인가 방식 확인 방법
      • 내 경우는 Kubernetes RBAC만을 사용하는 중
        내 경우는 Kubernetes RBAC만을 사용하는 중
      Azure RBAC를 사용하여 AKS의 비밀에 액세스하는 경우 다음 단계를 따릅니다.
      1. Azure CLI에 로그인합니다.
      2. 다음 명령을 실행하여 roledefinitionId에서 비밀에 대한 액세스를 허용하는 역할 할당을 식별합니다.
      az role definition list --scope /subscriptions/{subscription-id}/resourceGroups/{resource-group-name}/providers/Microsoft.ContainerService/managedClusters/{aks-cluster-name}
      3. 역할 작업
      Microsoft.ContainerService/managedCluster/*/read
      또는
      Microsoft.ContainerService/managedClusters/secrets/read
      를 사용하여 역할 정의를 검토합니다.
      4. 다음 명령을 실행하여 불필요한 역할, 할당된 사용자, 그룹 또는 Microsoft Entra ID 서비스 주체를 제거합니다.
      az role assignment delete --assignee {account-id} --scope /subscriptions/{subscription-id}/resourceGroups/{resource-group-name}/providers/Microsoft.ContainerService/managedClusters/{aks-cluster-name}
      Kubernetes RBAC를 사용하여 AKS에서 역할을 정의하는 경우
      1. Kubernetes 클러스터에 로그인합니다.
      2. 다음 명령을 실행하여 비밀에 액세스할 수 있는 역할을 식별합니다.
      kubectl get rolebindings --all-namespaces -o wide
      kubectl get clusterrolebindings -o wide
      3. 불필요한 rolebinding 및 clusterrolebindings를 제거하려면 다음 명령을 실행합니다.
      kubectl delete rolebinding {rolebinding-name} --namespace {namespace}
      kubectl delete clusterrolebinding {clusterrolebinding-name}

      수정 방안이 도움이 안된다..~!
      GPT로 Secret에 접근 가능한 ClusterRoleBinding, RoleBinding을 찾는 파워쉘 스크립트를 뽑았다.
      $clusterRoleBindings = kubectl get clusterrolebinding -o json | ConvertFrom-Json $clusterRoleBindings.items | Where-Object { $_.roleRef.kind -eq "ClusterRole" } | ForEach-Object { $roleName = $_.roleRef.name $clusterRole = kubectl get clusterrole $roleName -o json 2>$null | ConvertFrom-Json if ($clusterRole.rules.resources -contains "secrets") { Write-Output "ClusterRoleBinding: $($_.metadata.name) → ClusterRole: $roleName" Write-Output "Subjects: $($_.subjects | ConvertTo-Json -Compress)" } }
      클러스터 전체에서 Secret에 접근 가능한 ClusterRoleBinding 찾기
      $namespace = "<NAMESPACE>" $roleBindings = kubectl get rolebinding -n $namespace -o json | ConvertFrom-Json $roleBindings.items | Where-Object { $_.roleRef.kind -eq "Role" -or $_.roleRef.kind -eq "ClusterRole" } | ForEach-Object { $roleName = $_.roleRef.name $role = kubectl get role $roleName -n $namespace -o json 2>$null | ConvertFrom-Json if ($role.rules.resources -contains "secrets") { Write-Output "RoleBinding: $($_.metadata.name) → Role: $roleName" Write-Output "Subjects: $($_.subjects | ConvertTo-Json -Compress)" } }
      특정 네임스페이스에서 secret에 접근 가능한 RoleBinding, ClusterRoleBinding 찾기
      notion image
      리소스에 *도 포함된 바인딩이 있는지 확인해야할 듯

3️⃣서비스 계정 토큰은 AKS(Azure Kubernetes Service) 클러스터 Pod에 자동으로 탑재되어서는 안 됩니다.

클라우드용 Defender는 AKS 클러스터의 일부 Pod가 서비스 계정 토큰을 자동으로 탑재했음을 확인했습니다. 공격자가 탑재된 이러한 토큰을 오용할 수 있으므로 권한 상승 공격의 위험이 있습니다. 서비스 계정 토큰이 탑재된 Pod는 명시적 권한 부여 없이 다른 클러스터 리소스에 액세스할 수 있습니다. 이 위험을 완화하려면 서비스 계정 및 Pod에서 "automountServiceAccountToken"을 "false"로 설정하는 것이 좋습니다.
  • 수정 방안
    • AKS Pod 및 서비스 계정에서 서비스 계정 토큰의 자동 탑재를 사용하지 않도록 설정하려면:
      1. 명령 셸에서 다음 명령을 실행하여 automountServiceAccountToken을 사용하도록 설정한 서비스 계정을 식별합니다.
      kubectl get sa --all-namespaces -o yaml
      더 찾기 쉽게 GPT에 질의한 명령어
    • Powershell
      • kubectl get serviceaccount -A -o json | ConvertFrom-Json | Select-Object -ExpandProperty items | Where-Object { -not $_.PSObject.Properties["automountServiceAccountToken"] -or $_.automountServiceAccountToken -eq $true } | ForEach-Object { "$($_.metadata.namespace) $($_.metadata.name)" }
      2. automountServiceAccountToken 값을 false로 설정하여 서비스 계정을 편집합니다. 변경 내용을 적용하려면 다음을 실행합니다.
      kubectl apply -f [YOUR_SA_YAML_FILE_PATH]
      3. 다음을 실행하여 automountServiceAccountToken을 사용하도록 설정한 Pod를 식별합니다.
      kubectl get pods --all-namespaces -o yaml
    • Powershell
      • kubectl get pods -A -o json | ConvertFrom-Json | ForEach-Object { $_.items | ForEach-Object { if (-not $_.spec.automountServiceAccountToken -or $_.spec.automountServiceAccountToken -eq $true) { Write-Host "$($_.metadata.namespace) $($_.metadata.name)" } } }
        모든 네임스페이스에서 검색
      4. automountServiceAccountToken 값을 false로 설정하여 Pod를 편집합니다. 변경 내용을 적용하려면 다음을 실행합니다.
      kubectl apply -f [YOUR_POD_YAML_FILE_PATH]
      kubernetes 시스템이 작동하는 데 필요한 네임스페이스를 제외하고 업데이트가 필요한 각 서비스 계정 및 Pod에 대해 이 단계를 반복합니다.
 
위반 대상 자원이 엄청나게 많은데, 일부만 예외처리할 수도 없고.. 2️⃣,3️⃣같은 권장사항은 특히나 통과될 수가 없다고 봐야한다..
보면 알겠지만.. 제공하는 수정 방안이 다소 불친절하다.

마무리

MDC만으로 워크로드, 리소스 구성 점검을 완벽하게 할 수는 없다.. 경험해본 3rd Party 솔루션들이 더 많은 구성 점검 항목을 제공하기도 하고, 룰 또는 정책 커스텀에서 더 자유롭다. 어쩌면 굳이 MDC 유료 CSPM을 사용하지 않고 오픈소스를 사용하는게 더 나을 수도 있다.
그리고 권장사항은 무엇이 근거인지 쉽게 볼 수 없다는 점에서 가장 불편하다고 할 수 있다. 권장사항 완화 방법도 그닥 친절하진 않고, 세분화할 수 없다는점이 불편하다.. 많은걸 기대하지 않는게 좋다.
사실 AKS CIS 벤치마크도 제공된지 반년이 채 되지 않았다. 기능, 제공 권장사항 업데이트가 좀 더 빠르게 된다면 좋겠다는 생각이다.
커스텀이 제한적이지만, 이 말은 곧 솔루션이 사용자가 쉽게 사용할 수 있도록 유도하는것이라고 생각한다. 개인적으로는 보안 담당자가 코드로 정책 작성에 어려움이 있고, Azure만 사용하고, 관리할 워크로드가 많지 않다면 기본적인 보안 태세 확인용으로는 사용할만하지 않을까 싶다.