안녕하세요. 이 글은 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
'전공영역 공부 기록' 카테고리의 다른 글
[CKS] 클러스터 보안 - pod의 serviceaccount token (0) | 2022.01.24 |
---|---|
veleor minio 백업 연습 - 작성중 (0) | 2022.01.16 |
mariadb 인코딩 확인 명령어 (0) | 2022.01.09 |
디지털 인증서 (0) | 2022.01.04 |
ssh 공개키 인증 (0) | 2022.01.04 |