감사(Auditing)

감사(Auditing)

쿠버네티스 감사는 클러스터에서의 일련의 행동을 문서화하는 보안 관련, 시간순 기록 집합을 제공해요. 클러스터는 사용자, 쿠버네티스 API를 사용하는 애플리케이션, 그리고 컨트롤 플레인 자체가 생성한 활동을 감사해요.

감사를 통해 클러스터 관리자는 다음 질문에 답할 수 있어요.

  • 무슨 일이 일어났나?
  • 언제 일어났나?
  • 누가 시작했나?
  • 무엇에 대해 일어났나?
  • 어디서 관찰됐나?
  • 어디서 시작됐나?
  • 어디로 가고 있었나?

감사 기록은 kube-apiserver 컴포넌트 안에서 수명 주기를 시작해요. 실행의 각 단계의 각 요청은 감사 이벤트를 생성하고, 이는 특정 정책에 따라 사전 처리된 다음 백엔드에 기록돼요. 정책은 무엇이 기록될지 결정하고 백엔드는 기록을 지속시켜요. 현재 백엔드 구현에는 로그 파일과 웹훅이 포함돼요.

각 요청은 연관된 단계(stage)로 기록될 수 있어요. 정의된 단계는 다음과 같아요.

  • RequestReceived - 감사 핸들러가 요청을 수신하자마자, 그리고 핸들러 체인 아래로 위임되기 전에 생성되는 이벤트의 단계.
  • ResponseStarted - 응답 헤더가 전송된 후이지만 응답 본문이 전송되기 전. 이 단계는 장기 실행 요청(예: watch)에서만 생성돼요.
  • ResponseComplete - 응답 본문이 완료되었고 더 이상 바이트가 전송되지 않음.
  • Panic - 패닉이 발생했을 때 생성되는 이벤트.

참고: 감사 이벤트(Audit Event) 구성은 Event API 객체와 다르다는 점에 유의하세요.

감사 로깅 기능은 감사에 필요한 일부 컨텍스트가 각 요청에 대해 저장되기 때문에 API 서버의 메모리 소비를 증가시켜요. 메모리 소비는 감사 로깅 구성에 따라 달라져요.

출처: 문서

본문

감사 정책 (Audit policy)

감사 정책은 어떤 이벤트를 기록해야 하고 어떤 데이터를 포함해야 하는지에 대한 규칙을 정의해요. 감사 정책 객체 구조는 audit.k8s.io API 그룹에 정의돼 있어요. 이벤트가 처리될 때 규칙 목록과 순서대로 비교돼요. 첫 번째 일치 규칙이 이벤트의 감사 수준을 설정해요. 정의된 감사 수준은 다음과 같아요.

  • None - 이 규칙과 일치하는 이벤트를 기록하지 않음.
  • Metadata - 메타데이터(요청 사용자, 타임스탬프, 리소스, 동사 등)로 이벤트를 기록하지만 요청 또는 응답 본문은 기록하지 않음.
  • Request - 요청 메타데이터와 본문으로 이벤트를 기록하지만 응답 본문은 기록하지 않음. 비리소스 요청에는 적용되지 않음.
  • RequestResponse - 요청 메타데이터, 요청 본문, 응답 본문으로 이벤트를 기록함. 비리소스 요청에는 적용되지 않음.

--audit-policy-file 플래그로 정책이 있는 파일을 kube-apiserver에 전달할 수 있어요. 이 플래그를 생략하면 어떤 이벤트도 기록되지 않아요. 감사 정책 파일에는 rules 필드가 반드시 제공돼야 한다는 점에 유의하세요. 규칙이 0개인 정책은 불법으로 취급돼요.

다음은 감사 정책 파일의 예시예요.

apiVersion: audit.k8s.io/v1 # This is required.
kind: Policy
# Don't generate audit events for all requests in RequestReceived stage.
omitStages:
  - "RequestReceived"
rules:
  # Log pod changes at RequestResponse level
  - level: RequestResponse
    resources:
    - group: ""
      # Resource "pods" doesn't match requests to any subresource of pods,
      # which is consistent with the RBAC policy.
      resources: ["pods"]
  # Log "pods/log", "pods/status" at Metadata level
  - level: Metadata
    resources:
    - group: ""
      resources: ["pods/log", "pods/status"]

  # Don't log requests to a configmap called "controller-leader"
  - level: None
    resources:
    - group: ""
      resources: ["configmaps"]
      resourceNames: ["controller-leader"]

  # Don't log watch requests by the "system:kube-proxy" on endpoints or services
  - level: None
    users: ["system:kube-proxy"]
    verbs: ["watch"]
    resources:
    - group: "" # core API group
      resources: ["endpoints", "services"]

  # Don't log authenticated requests to certain non-resource URL paths.
  - level: None
    userGroups: ["system:authenticated"]
    nonResourceURLs:
    - "/api*" # Wildcard matching.
    - "/version"

  # Log the request body of configmap changes in kube-system.
  - level: Request
    resources:
    - group: "" # core API group
      resources: ["configmaps"]
    # This rule only applies to resources in the "kube-system" namespace.
    # The empty string "" can be used to select non-namespaced resources.
    namespaces: ["kube-system"]

  # Log configmap and secret changes in all other namespaces at the Metadata level.
  - level: Metadata
    resources:
    - group: "" # core API group
      resources: ["secrets", "configmaps"]

  # Log all other resources in core and extensions at the Request level.
  - level: Request
    resources:
    - group: "" # core API group
    - group: "extensions" # Version of group should NOT be included.

  # A catch-all rule to log all other requests at the Metadata level.
  - level: Metadata
    # Long-running requests like watches that fall under this rule will not
    # generate an audit event in RequestReceived.
    omitStages:
      - "RequestReceived"

모든 요청을 Metadata 수준으로 기록하려면 최소한의 감사 정책 파일을 사용할 수 있어요.

# Log all requests at the Metadata level.
apiVersion: audit.k8s.io/v1
kind: Policy
rules:
- level: Metadata

자체 감사 프로필을 만든다면 Google Container-Optimized OS용 감사 프로필을 출발점으로 사용할 수 있어요. 감사 정책 파일을 생성하는 configure-helper.sh 스크립트를 확인할 수 있어요.

Policy 구성 참조를 보면 정의된 필드에 대한 자세한 내용을 확인할 수 있어요.

감사 백엔드 (Audit backends)

감사 백엔드는 감사 이벤트를 외부 저장소에 지속시켜요. 기본적으로 kube-apiserver는 두 개의 백엔드를 제공해요.

  • 로그 백엔드: 파일시스템에 이벤트를 기록함.
  • 웹훅 백엔드: 외부 HTTP API에 이벤트를 보냄.

모든 경우에 감사 이벤트는 audit.k8s.io API 그룹에서 쿠버네티스 API가 정의한 구조를 따르는 여러 단계에서 생성돼요.

참고: 패치의 경우 요청 본문은 적절한 쿠버네티스 API 객체가 있는 JSON 객체가 아니라 패치 연산이 있는 JSON 배열이에요. 예를 들어 다음 요청 본문은 /apis/batch/v1/namespaces/some-namespace/jobs/some-job-name에 대한 유효한 패치 요청이에요.

[
  {
    "op": "replace",
    "path": "/spec/parallelism",
    "value": 0
  },
  {
    "op": "remove",
    "path": "/spec/template/spec/containers/0/terminationMessagePolicy"
  }
]

로그 백엔드 (Log backend)

로그 백엔드는 감사 이벤트를 JSONlines 형식의 파일에 기록해요. 다음 kube-apiserver 플래그로 로그 감사 백엔드를 구성할 수 있어요.

  • --audit-log-path는 로그 백엔드가 감사 이벤트를 기록하는 데 사용하는 로그 파일 경로를 지정해요. 이 플래그를 지정하지 않으면 로그 백엔드가 비활성화돼요. -는 표준 출력을 의미해요.
  • --audit-log-maxage는 오래된 감사 로그 파일을 보존할 최대 일수를 정의해요.
  • --audit-log-maxbackup은 보존할 감사 로그 파일의 최대 수를 정의해요.
  • --audit-log-maxsize는 회전되기 전의 감사 로그 파일의 최대 크기를 메가바이트로 정의해요.

클러스터의 컨트롤 플레인이 kube-apiserver를 Pod로 실행한다면, 감사 기록이 지속되도록 정책 파일과 로그 파일의 위치에 hostPath를 마운트하는 것을 기억하세요. 예를 들어:

  - --audit-policy-file=/etc/kubernetes/audit-policy.yaml
  - --audit-log-path=/var/log/kubernetes/audit/audit.log

그런 다음 볼륨을 마운트해요.

...
volumeMounts:
  - mountPath: /etc/kubernetes/audit-policy.yaml
    name: audit
    readOnly: true
  - mountPath: /var/log/kubernetes/audit/
    name: audit-log
    readOnly: false

마지막으로 hostPath를 구성해요.

...
volumes:
- name: audit
  hostPath:
    path: /etc/kubernetes/audit-policy.yaml
    type: File

- name: audit-log
  hostPath:
    path: /var/log/kubernetes/audit/
    type: DirectoryOrCreate

웹훅 백엔드 (Webhook backend)

웹훅 감사 백엔드는 감사 이벤트를 원격 웹 API로 보내는데, 이는 인증 수단을 포함한 쿠버네티스 API의 한 형태로 간주돼요. 다음 kube-apiserver 플래그로 웹훅 감사 백엔드를 구성할 수 있어요.

  • --audit-webhook-config-file은 웹훅 구성이 있는 파일의 경로를 지정해요. 웹훅 구성은 사실상 특수화된 kubeconfig예요.
  • --audit-webhook-initial-backoff는 첫 번째 실패 요청 후 재시도 전에 기다릴 시간을 지정해요. 후속 요청은 지수 백오프로 재시도돼요.

웹훅 구성 파일은 kubeconfig 형식을 사용해 서비스의 원격 주소와 연결에 사용되는 자격 증명을 지정해요.

이벤트 일괄 처리 (Event batching)

logwebhook 백엔드 모두 일괄 처리(batching)를 지원해요. 각 백엔드에 특정한 사용 가능한 플래그 목록이 아래에 있어요. 기본적으로 일괄 처리와 스로틀링은 webhook 백엔드에서 활성화되고 log 백엔드에서는 비활성화돼요.

  • --audit-webhook-mode는 버퍼링 전략을 정의해요. batch: 이벤트를 버퍼링하고 비동기로 일괄 처리. webhook 백엔드의 기본 모드. blocking: 각 개별 이벤트 처리 시 API 서버 응답을 차단. blocking-strict: blocking과 같지만 RequestReceived 단계에서 감사 로깅 중 실패가 있으면 kube-apiserver에 대한 전체 요청이 실패.

다음 플래그는 batch 모드에서만 사용돼요.

  • --audit-webhook-batch-buffer-size는 일괄 처리 전에 버퍼링할 이벤트 수를 정의해요. 들어오는 이벤트의 속도가 버퍼를 넘치게 하면 이벤트가 버려져요. 기본값은 10000.
  • --audit-webhook-batch-max-size는 하나의 배치에 있는 이벤트의 최대 수를 정의해요. 기본값은 400.
  • --audit-webhook-batch-max-wait는 큐의 이벤트를 무조건 일괄 처리하기 전에 기다리는 최대 시간을 정의해요. 기본값은 30초.
  • --audit-webhook-batch-throttle-enable은 일괄 처리 스로틀링이 활성화되었는지 정의해요. 스로틀링은 기본적으로 활성화됨.
  • --audit-webhook-batch-throttle-qps는 초당 생성되는 배치의 최대 평균 수를 정의해요. 기본값은 10.
  • --audit-webhook-batch-throttle-burst는 이전에 허용된 QPS가 충분히 사용되지 않았다면 같은 순간에 생성되는 배치의 최대 수를 정의해요. 기본값은 15.
  • --audit-log-mode는 버퍼링 전략을 정의해요. batch: 이벤트를 버퍼링하고 비동기로 일괄 처리. log 백엔드에는 일괄 처리를 권장하지 않아요. blocking: 각 개별 이벤트 처리 시 API 서버 응답을 차단. log 백엔드의 기본 모드. blocking-strict: blocking과 같지만 RequestReceived 단계에서 감사 로깅 중 실패가 있으면 kube-apiserver에 대한 전체 요청이 실패.

다음 플래그는 batch 모드에서만 사용돼요(log 백엔드에서는 기본적으로 일괄 처리가 비활성화되어 있으며, 일괄 처리가 비활성화되면 모든 일괄 처리 관련 플래그는 무시돼요).

  • --audit-log-batch-buffer-size는 일괄 처리 전에 버퍼링할 이벤트 수를 정의해요. 들어오는 이벤트의 속도가 버퍼를 넘치게 하면 이벤트가 버려져요.
  • --audit-log-batch-max-size는 하나의 배치에 있는 이벤트의 최대 수를 정의해요.
  • --audit-log-batch-max-wait는 큐의 이벤트를 무조건 일괄 처리하기 전에 기다리는 최대 시간을 정의해요.
  • --audit-log-batch-throttle-enable은 일괄 처리 스로틀링이 활성화되었는지 정의해요.
  • --audit-log-batch-throttle-qps는 초당 생성되는 배치의 최대 평균 수를 정의해요.
  • --audit-log-batch-throttle-burst는 이전에 허용된 QPS가 충분히 사용되지 않았다면 같은 순간에 생성되는 배치의 최대 수를 정의해요.

매개변수 튜닝 (Parameter tuning)

매개변수는 API 서버의 부하를 수용하도록 설정해야 해요. 예를 들어 kube-apiserver가 매초 100개의 요청을 받고 각 요청이 ResponseStartedResponseComplete 단계에서만 감사된다면, 매초 약 200개의 감사 이벤트가 생성되는 것을 고려해야 해요. 배치에 최대 100개의 이벤트가 있다고 가정하면 스로틀링 수준을 최소 초당 2개 쿼리로 설정해야 해요. 백엔드가 이벤트를 기록하는 데 최대 5초가 걸린다고 가정하면 버퍼 크기를 최대 5초의 이벤트, 즉 10개 배치 또는 1000개 이벤트를 보유하도록 설정해야 해요.

하지만 대부분의 경우 기본 매개변수로 충분하며 수동으로 설정하는 것에 대해 걱정할 필요가 없어요. kube-apiserver가 노출하는 다음 Prometheus 메트릭과 로그에서 감사 서브시스템의 상태를 모니터링할 수 있어요.

  • apiserver_audit_event_total 메트릭은 내보낸 감사 이벤트의 총 수를 포함해요.
  • apiserver_audit_error_total 메트릭은 내보내기 중 오류로 인해 버려진 이벤트의 총 수를 포함해요.

로그 항목 잘림 (Log entry truncation)

로그 및 웹훅 백엔드 모두 기록되는 이벤트의 크기를 제한하는 것을 지원해요. 예를 들어 다음은 로그 백엔드에서 사용 가능한 플래그 목록이에요.

  • audit-log-truncate-enabled 이벤트 및 배치 잘림이 활성화되었는지 여부.
  • audit-log-truncate-max-batch-size 기본 백엔드로 보내는 배치의 최대 크기(바이트).
  • audit-log-truncate-max-event-size 기본 백엔드로 보내는 감사 이벤트의 최대 크기(바이트).

기본적으로 잘림은 webhooklog 모두에서 비활성화되어 있어요. 클러스터 관리자는 기능을 활성화하기 위해 audit-log-truncate-enabled 또는 audit-webhook-truncate-enabled를 설정해야 해요.

다음 단계 (What's next)

  • Mutating webhook 감사 어노테이션에 대해 알아보기.
  • Audit 구성 참조를 읽어 EventPolicy 리소스 유형에 대해 더 알아보기.

더 알아보기 (Learn more)