AppArmor로 컨테이너 보호

AppArmor는 호스트 운영체제에서 실행되는 프로세스의 기능을 제한하는 데 사용할 수 있는 Linux 커널 보안 모듈입니다. 각 프로세스는 자체 보안 프로필을 가질 수 있습니다. 보안 프로필은 네트워크 액세스 또는 파일 읽기/쓰기/ 실행 권한과 같은 특정 기능을 허용하거나 허용하지 않습니다.

Container-Optimized OS 인스턴스에서 실행 중인 Docker 컨테이너에 AppArmor를 사용할 수 있습니다. 특정 컨테이너에서 Docker에 포함된 기본 AppArmor 보안 프로필을 적용하거나 사용자가 제공한 커스텀 보안 프로필을 적용할 수 있습니다.

기본 Docker AppArmor 보안 프로필 사용

Container-Optimized OS 인스턴스에서 컨테이너를 시작하면 시스템이 docker-default AppArmor 보안 프로필을 자동으로 적용합니다. 다음 예시 명령어는 docker-default 보안 프로필로 컨테이너를 실행합니다.

docker run --rm -it debian:jessie bash -i

docker-default 보안 프로필을 테스트하기 위해 다음과 같이 cat 명령어로 /proc/sysrq-trigger 파일을 읽으려고 시도할 수 있습니다.

root@88cef496c1a5:/# cat /proc/sysrq-trigger

출력에는 다음과 유사한 'Permission Denied' 오류가 있어야 합니다.

cat: /proc/sysrq-trigger: Permission denied

커스텀 보안 프로필 적용

다른 보안 프로필을 적용하려면 컨테이너를 실행할 때 apparmor=<profile-name> 명령줄 옵션을 사용하세요. 다음 예시 명령어는 no-ping이라는 보안 프로필로 컨테이너를 실행합니다.

docker run --rm -i --security-opt apparmor=no-ping debian:jessie bash -i

예시에 지정된 no-ping 프로필을 만드는 방법에 대한 자세한 정보는 이 주제의 뒷부분에 있는 커스텀 보안 프로필 만들기를 참조하세요.

다음 예시와 같이 apparmor 옵션으로 unconfined을 지정하여 컨테이너가 보안 프로필을 사용하지 않고 실행되었음을 나타낼 수도 있습니다.

docker run --rm -it --security-opt apparmor=unconfined debian:jessie bash -i

활성 AppArmor 보안 프로필 보기

/proc/<pid>/attr/current 파일을 검사하여 Container-Optimized OS 인스턴스의 프로세스에 적용되는 AppArmor 프로필(있는 경우)을 확인할 수 있습니다. 여기서 <pid>은 프로세스 ID입니다.

ps -ef | grep '[b]ash -i' 명령어로 표시된 인스턴스에서 다음 프로세스가 실행 중이라고 가정하겠습니다.

root      1903  1897  0 21:58 pts/3    00:00:00 docker run --rm -it debian:jessie bash -i
root      1927  1913  0 21:58 pts/4    00:00:00 bash -i
root      1978  1001  0 22:01 pts/0    00:00:00 docker run --rm -it --security-opt apparmor=unconfined debian:jessie bash -i
root      2001  1988  0 22:01 pts/2    00:00:00 bash -i

/proc/1927/attr/current을 검사하면 기본 Docker 보안 프로필로 프로세스(pid 1927)가 실행되었음을 나타내는 다음과 같은 출력을 볼 수 있습니다.

# cat /proc/1927/attr/current
docker-default (enforce)

/proc/2001/attr/current을 검사하면 보안 프로필을 사용하지 않고(즉 apparmor=unconfined 옵션을 사용하여) 프로세스(pid 2001)가 실행되었음을 나타내는 다음 결과가 표시됩니다.

# cat /proc/2001/attr/current
unconfined

커스텀 보안 프로필 만들기

docker-default와 상이한 보안 프로필이 프로세스에 필요한 경우 고유한 커스텀 프로필을 만들 수 있습니다. 커스텀 프로필을 사용하려면 프로필을 만든 다음 해당 파일을 AppArmor에 로드해야 합니다.

예를 들어 모든 원시 네트워크 트래픽을 허용하지 않는 보안 프로필이 필요하다고 가정해 보겠습니다. 다음 스크립트는 /etc/apparmor.d/no_raw_netno-ping이라는 보안 프로필의 파일을 만듭니다.

cat > /etc/apparmor.d/no_raw_net <<EOF
#include <tunables/global>

profile no-ping flags=(attach_disconnected,mediate_deleted) {
  #include <abstractions/base>

  network inet tcp,
  network inet udp,
  network inet icmp,

  deny network raw,
  deny network packet,
  file,
  mount,
}
EOF

보안 프로필 파일을 만든 후 apparmor_parser을 사용하여 프로필을 AppArmor에 로드할 수 있습니다.

/sbin/apparmor_parser --replace --write-cache /etc/apparmor.d/no_raw_net

로드된 후에는 다음과 같이 no-ping 프로필을 테스트할 수 있습니다.

$ docker run --rm -i --security-opt apparmor=no-ping debian:jessie ping -c3 8.8.8.8

이 명령어는 no-ping 보안 프로필로 컨테이너를 만들고 컨테이너 내에서 ping을 실행하려고 시도합니다. 보안 프로필은 다음과 같은 오류를 유발하는 트래픽을 허용하지 않아야 합니다.

ping: Lacking privilege for raw socket.

Container-Optimized OS 인스턴스 부팅 시 커스텀 보안 프로필이 존재하고 재부팅 후에도 지속되도록 cloud-init을 사용하여 /etc/apparmor.d에 프로필을 설치할 수 있습니다. 이를 위해 user-data 키 값으로 인스턴스 메타데이터에 cloud-config 스크립트를 추가합니다.

다음 cloud-config 스크립트는 no-ping 프로필을 /etc/apparmor.d에 추가합니다.

#cloud-configs

write_files:
- path: /etc/apparmor.d/no_raw_net
  permissions: 0644
  owner: root
  content: |
    #include <tunables/global>

    profile no-ping flags=(attach_disconnected,mediate_deleted) {
      #include <abstractions/base>

      network inet tcp,
      network inet udp,
      network inet icmp,

      deny network raw,
      deny network packet,
      file,
      mount,
    }

서비스 파일이 AppArmor에 커스텀 프로필을 로드하고 Docker에 사용하라는 지시를 전달하도록 하려면 인스턴스에서 다음 명령어를 실행하세요.

ExecStartPre=/sbin/apparmor_parser -r -W /etc/apparmor.d/no_raw_net
ExecStart=/usr/bin/docker run --security-opt apparmor=no-ping ...

명령어를 실행한 후 인스턴스를 재부팅하면 커스텀 AppArmor 프로필로 제한된 컨테이너를 실행할 수 있습니다.