전공영역 공부 기록

[CKS] 시스템 보안 - App armor

악분 2022. 1. 16. 02:17
반응형

안녕하세요. 이 글은 CKS자격증 공부를 하면서 정리한 글입니다.

 

1. App Armor개요

1.1 정의

application armor의 줄일말로 애플리케이션을 보호하는 리눅스 커널 보안 모듈입니다. 애플리케이션이 실행 전 행동을 검사하고 실행여부를 결정합니다. 검사와 실행여부를 결정하는 설정을 프로파일이라고 부릅니다. 프로파일은 /etc/apparmor.d에 위치하고 있습니다.

1.2 설치

app armor은 수세(Suse), 데비안(Debian), 우분투(Ubuntu) 리눅스 특정버전 이상부터 기본적으로 설치되어 있습니다. 우분투는 7.10이상부터 설치되어 있는 것같습니다.

 

systemctl을 app armor을 시작할 수 있습니다. 

systemctl start apparmor
systemctl status apparmor

 

app armor을 편하게 사용하기 위한 유틸리티 도구(프로파일 생성, 프로파일 조회 등)를 옵션으로 설치해서 사용합니다. 

apt-get install apparmor-utils

 

1.3 실행모드

모드이름 기능
enforce mode 허용되지 않은 동작을 제한하고 로그를 남깁니다. 로그 저장위치는 syslog(/var/log/syslog)에 저장됩니다.
complain mode 동작은 제한하지 않고 로그만 남깁니다. 로그 저장위치는 syslog(/var/log/syslog)에 저장됩니다.
unconfined mode 정확하지 않지만 동작도 제한하지 않고 로그도 남기지 않습니다.

 

2. 명령어 정리

2.1 프로파일 목록 조회

aa-status는 enforce, complain, unconfined 모드에 있는 프로파일을 조회합니다.

aa-status

 

2.2 프로파일 생성

aa-genprof는 enforce mode로 프로파일을 추가합니다.

aa-genprof [명령어]
ex) app-genprof curl

 

2.3 프로파일 로그 조회

app armor 프로파일이 차단한 로그를 조회합니다. 그리고 대화형 인터페이스로 로그에 기록된 행동을 허용할지 결정할 수 있습니다. 실습단계에서 자세히 살펴봅니다.

aa-logprof

 

3. 실습

curl명령어 실행여부를 제어하는 실습을 진행합니다.

 

3.1 app armor 실행

systemctl로 app armor를 실행합니다.

 

3.2 curl 명령어 확인

curl을 app-armor로 보호하기 이전에 구글서버를 대상으로 curl명령어가 잘 실행되는지 확인합니다.

curl google.com

 

3.3 프로파일 생성

aa-genprof명령어를 이용하여 enforce모드 프로파일을 생성합니다. 중간에 입력 프롬프트를 대기하는데 F를 눌러 Finish옵션을 선택합니다. 

aa-genprof curl

 

aa-status로 curl프로파일이 생성되었는지 확인합니다.

 

curl 프로파일은 /etc/apparmor.d에 존재합니다.

 

3.4 curl 명령어 실행확인

app armor에 curl프로파일이 추가되었고 모든 행동이 제약설정이 되어있습니다. 그러므로 curl명령어를 실행할 때 제대로 수행되지 않습니다.

curl google.com

 

3.5 curl 명령어 허용설정

저희가 원하는 것은 curl의 모든 행동을 제한하는 것이 아니므로 수정이 필요합니다. aa-logprof를 실행하면 /var/log/syslog를 분석하여 app armor가 행동을 제한한 로그를 가져옵니다. 그리고 프로파일을 수정하는 대화형 프롬프트가 실행됩니다. 

 

curl명령어를 접근한 /etc/ssl/openssl.cnf와 /etc/hosts.conf가 차단되었다는 메세지를 화면에 출력됩니다. (A)llow를 선택하면 해당 파일에 대한 접근을 허용하겠다는 의미입니다. 행동을 제한한 것들을 모두 (A)llow를 설정합니다.

aa-logprof

 

3.6 curl명령어 확인

curl에 대한 행동을 모드 허용했으므로 이제 curl명령어가 잘 실행됩니다.

curl google.com

 

4. 쿠버네티스 app armor

4.1 실행조건

쿠버네티스 app armor를 실행하기 위해서는 조건이 충족해야 합니다.

  • CRI(Container Runtime Interface)가 app armor을 지원해야 한다.
  • 모든 노드(controlplane 옵션)에 app armor을 실행 하고 있어야 한다.
  • 모든 노드(controlplane 옵션)에 app armor 프로파일이 존재해야 한다.
  • app armor은 pod의 컨테이너 단위로 적용해야 한다.

 

모든 노드에 프로파일이 존재해야 하기 때문에 데몬셋으로 프로파일을 설정하는 사례도 있습니다. 대표적으로 구글에서 관리하는 apparmor-loader 이미지(https://hub.docker.com/r/google/apparmor-loader)가 있습니다.

 

4.2 프로파일 생성

참고자료: https://github.com/GoogleCloudPlatform/gke-security-scenarios-demo/blob/master/terraform/modules/instance/manifests/apparmor-loader.yaml

데몬셋으로 프로파일을 관리할 것이기 때문에 프로파일은 쿠버네티스 configmap으로 생성합니다.

 

 

먼저 apparmor namespace를 생성합니다.

kubectl create ns apparmor

 

그리고 프로파일을 configmap으로 생성합니다. 

apiVersion: v1
# https://kubernetes.io/docs/tasks/configure-pod-container/configure-pod-configmap/#create-a-configmap
kind: ConfigMap
metadata:
  name: apparmor-profiles
  namespace: apparmor
data:
  # Filename k8s-nginx maps to the definition of the nginx profile.
  k8s-nginx: |-
    #include <tunables/global>
    # From https://github.com/jfrazelle/bane/blob/master/docker-nginx-sample
    profile k8s-nginx flags=(attach_disconnected,mediate_deleted) {
      #include <abstractions/base>
      network inet tcp,
      network inet udp,
      network inet icmp,
      deny network raw,
      deny network packet,
      file,
      umount,
      deny /bin/** wl,
      deny /boot/** wl,
      deny /dev/** wl,
      deny /etc/** wl,
      deny /home/** wl,
      deny /lib/** wl,
      deny /lib64/** wl,
      deny /media/** wl,
      deny /mnt/** wl,
      deny /opt/** wl,
      deny /proc/** wl,
      deny /root/** wl,
      deny /sbin/** wl,
      deny /srv/** wl,
      deny /tmp/** wl,
      deny /sys/** wl,
      deny /usr/** wl,
      audit /** w,
      /var/run/nginx.pid w,
      /usr/sbin/nginx ix,
      deny /bin/dash mrwklx,
      deny /bin/sh mrwklx,
      deny /usr/bin/top mrwklx,
      capability chown,
      capability dac_override,
      capability setuid,
      capability setgid,
      capability net_bind_service,
      deny @{PROC}/{*,**^[0-9*],sys/kernel/shm*} wkx,
      deny @{PROC}/sysrq-trigger rwklx,
      deny @{PROC}/mem rwklx,
      deny @{PROC}/kmem rwklx,
      deny @{PROC}/kcore rwklx,
      deny mount,
      deny /sys/[^f]*/** wklx,
      deny /sys/f[^s]*/** wklx,
      deny /sys/fs/[^c]*/** wklx,
      deny /sys/fs/c[^g]*/** wklx,
      deny /sys/fs/cg[^r]*/** wklx,
      deny /sys/firmware/efi/efivars/** rwklx,
      deny /sys/kernel/security/** rwklx,
    }

 

4.3 apparmor loader 데몬셋 실행

google apparmor-loader을 데몬셋으로 실행하여 모든 노드의 프로파일을 관리합니다.

  • 기존에 노드에 있는 app armor(/etc/apparmor.d)프로파일을 읽기전용으로 로드
  • configmap으로 정의한 프로파일은 /profiles디렉터리에 마운트
  • 30초에 한번씩 프로파일 동기화. 단, 새로운 프로파일은 추가되지만 삭제는 불가
apiVersion: apps/v1
kind: DaemonSet
metadata:
  name: apparmor-loader
  # Namespace must match that of the ConfigMap.
  namespace: apparmor
spec:
  selector:
    matchLabels:
      daemon: apparmor-loader
  template:
    metadata:
      name: apparmor-loader
      labels:
        daemon: apparmor-loader
    spec:
      # Do not mount a service account token, since these pods do not access the Kubernetes API
      automountServiceAccountToken: false
      containers:
      - name: apparmor-loader
        image: gcr.io/google-containers/apparmor-loader:0.2
        args:
          # Tell the loader to pull the /profiles directory every 30 seconds.
          - -poll
          - 30s
          - /profiles
        securityContext:
          # The loader requires root permissions to actually load the profiles.
          privileged: true
        volumeMounts:
        - name: sys
          mountPath: /sys
          readOnly: true
        - name: apparmor-includes
          mountPath: /etc/apparmor.d
          readOnly: true
        - name: profiles
          mountPath: /profiles
          readOnly: true
      volumes:
      # The /sys directory must be mounted to interact with the AppArmor module.
      - name: sys
        hostPath:
          path: /sys
      # The /etc/apparmor.d directory is required for most apparmor include templates.
      - name: apparmor-includes
        hostPath:
          path: /etc/apparmor.d
      # Map in the profile data.
      - name: profiles
        configMap:
          name: apparmor-profiles

 

저는 워커노드가 2개여서 2개의 데몬셋이 실행되었습니다.

kubectl get po -n apparmor

 

app armor로더 pod의 /profiles디렉터리에 configmap으로 정의한 프로파일이 존재합니다.

kubectl exec -it -n apparmor apparmor-loader-6czpb -- ls /profiles

 

4.4 app armor가 설정된 pod실행

참고자료: https://kubernetes.io/ko/docs/tutorials/clusters/apparmor/#securing-a-pod

 

app armor은 애노테이션으로 설정할 수 있습니다. 주의사항은 컨테이너 이름을 정확히 설정해야 합니다. 아래는 nginx컨테이너에 app armor 프로파일을 설정했습니다.

apiVersion: v1
kind: Pod
metadata:
  annotations:
    # nginx는 컨테이너 이름
    container.apparmor.security.beta.kubernetes.io/nginx: localhost/k8s-nginx
  name: nginx-secure
spec:
  containers:
  - image: nginx
    name: nginx
    resources: {}
  dnsPolicy: ClusterFirst
  restartPolicy: Always
status: {}

 

4.5 pod쉘에서 app armor행동제한 확인

nginx-secure pod쉘에 접속하여 sh쉘, /root경로에 파일을 생성하면 거부됩니다.

kubectl exec -it nginx-secure -- /bin/bash
root@nginx-secure:/# sh
root@nginx-secure:/# touch /root/hello.txt

 

그 이유는 nginx 컨테이너 생성된 app armor에 행동제한 규칙이 있기 때문입니다.

apiVersion: v1
kind: ConfigMap
metadata:
  name: apparmor-profiles
  namespace: apparmor
data:
  k8s-nginx: |-
    #include <tunables/global>
    # From https://github.com/jfrazelle/bane/blob/master/docker-nginx-sample
    profile k8s-nginx flags=(attach_disconnected,mediate_deleted) {
      #include <abstractions/base>
      ...
      deny /root/** wl,
      ...
      deny /bin/sh mrwklx,
      ...
    }

 

5. 참고자료

[1] [쿠버네티스 공식문서] https://kubernetes.io/ko/docs/tutorials/clusters/apparmor/

[2] [마이크로소프트 문서] https://docs.microsoft.com/ko-kr/azure/aks/operator-best-practices-cluster-security

[3] [블로그] https://themitigators.com/index.php/2019/02/17/apparmor-a-linux-security-modulelsm/

[4] [app armor gitlab] https://gitlab.com/apparmor/apparmor/-/wikis/Profiling_with_tools

[5] [블로그] https://tbhaxor.com/mitigating-the-damage-in-the-compromised-webserver-using-apparmor/

[6] [블로그] https://ssup2.github.io/theory_analysis/AppArmor/

[7] [유투브] https://www.youtube.com/watch?v=KYM-Dzivnjs 

[8] [medium] https://betterprogramming.pub/secure-your-kubernetes-cluster-with-apparmor-e4bb9fef37e1

[9] [github] app-armor loader yaml -https://github.com/GoogleCloudPlatform/gke-security-scenarios-demo/blob/master/terraform/modules/instance/manifests/apparmor-loader.yaml

반응형