Information in this document may be out of date

This document has an older update date than the original, so the information it contains may be out of date. If you're able to read English, see the English version for the most up-to-date information: Restrict a Container's Access to Resources with AppArmor

AppArmor๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ๋ฆฌ์†Œ์Šค์— ๋Œ€ํ•œ ์ปจํ…Œ์ด๋„ˆ์˜ ์ ‘๊ทผ ์ œํ•œ

๊ธฐ๋Šฅ ์ƒํƒœ: Kubernetes v1.4 [beta]

AppArmor๋Š” ํ‘œ์ค€ ๋ฆฌ๋ˆ…์Šค ์‚ฌ์šฉ์ž์™€ ๊ทธ๋ฃน ๊ธฐ๋ฐ˜์˜ ๊ถŒํ•œ์„ ๋ณด์™„ํ•˜์—ฌ, ํ•œ์ •๋œ ๋ฆฌ์†Œ์Šค ์ง‘ํ•ฉ์œผ๋กœ ํ”„๋กœ๊ทธ๋žจ์„ ์ œํ•œํ•˜๋Š” ๋ฆฌ๋ˆ…์Šค ์ปค๋„ ๋ณด์•ˆ ๋ชจ๋“ˆ์ด๋‹ค. AppArmor๋Š” ์ž„์˜์˜ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์— ๋Œ€ํ•ด์„œ ์ž ์žฌ์ ์ธ ๊ณต๊ฒฉ ๋ฒ”์œ„๋ฅผ ์ค„์ด๊ณ  ๋”์šฑ ์‹ฌ์ธต์ ์ธ ๋ฐฉ์–ด๋ฅผ ์ œ๊ณตํ•˜๋„๋ก ๊ตฌ์„ฑํ•  ์ˆ˜ ์žˆ๋‹ค. ์ด ๊ธฐ๋Šฅ์€ ํŠน์ • ํ”„๋กœ๊ทธ๋žจ์ด๋‚˜ ์ปจํ…Œ์ด๋„ˆ์—์„œ ํ•„์š”ํ•œ ๋ฆฌ๋ˆ…์Šค ๊ธฐ๋Šฅ, ๋„คํŠธ์›Œํฌ ์‚ฌ์šฉ, ํŒŒ์ผ ๊ถŒํ•œ ๋“ฑ์— ๋Œ€ํ•œ ์ ‘๊ทผ์„ ํ—ˆ์šฉํ•˜๋Š” ํ”„๋กœํŒŒ์ผ๋กœ ๊ตฌ์„ฑํ•œ๋‹ค. ๊ฐ ํ”„๋กœํŒŒ์ผ์€ ํ—ˆ์šฉํ•˜์ง€ ์•Š์€ ๋ฆฌ์†Œ์Šค ์ ‘๊ทผ์„ ์ฐจ๋‹จํ•˜๋Š” ๊ฐ•์ œ(enforcing) ๋ชจ๋“œ ๋˜๋Š” ์œ„๋ฐ˜๋งŒ์„ ๋ณด๊ณ ํ•˜๋Š” ๋ถˆํ‰(complain) ๋ชจ๋“œ๋กœ ์‹คํ–‰ํ•  ์ˆ˜ ์žˆ๋‹ค.

AppArmor๋ฅผ ์ด์šฉํ•˜๋ฉด ์ปจํ…Œ์ด๋„ˆ๊ฐ€ ์ˆ˜ํ–‰ํ•  ์ˆ˜ ์žˆ๋Š” ์ž‘์—…์„ ์ œํ•œํ•˜๊ณ  ๋˜๋Š” ์‹œ์Šคํ…œ ๋กœ๊ทธ๋ฅผ ํ†ตํ•ด ๋” ๋‚˜์€ ๊ฐ์‚ฌ๋ฅผ ์ œ๊ณตํ•˜์—ฌ ๋” ์•ˆ์ „ํ•œ ๋ฐฐํฌ๋ฅผ ์‹คํ–‰ํ•  ์ˆ˜ ์žˆ๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ AppArmor๊ฐ€ ์€ํƒ„ํ™˜(์–ธ์ œ๋‚˜ ํ†ตํ•˜๋Š” ๋ฌด์ ์˜ ๋ฐฉ๋ฒ•)์ด ์•„๋‹ˆ๋ฉฐ, ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ์ฝ”๋“œ ์ทจ์•ฝ์ ์„ ๋ณดํ˜ธํ•˜๊ธฐ ์œ„ํ•œ ์—ฌ๋Ÿฌ ์กฐ์น˜๋ฅผ ํ•  ์ˆ˜ ์žˆ๋Š” ๊ฒƒ ๋ฟ์ž„์„ ์žŠ์œผ๋ฉด ์•ˆ๋œ๋‹ค. ์–‘ํ˜ธํ•˜๊ณ  ์ œํ•œ์ ์ธ ํ”„๋กœํŒŒ์ผ์„ ์ œ๊ณตํ•˜๊ณ , ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜๊ณผ ํด๋Ÿฌ์Šคํ„ฐ๋ฅผ ์—ฌ๋Ÿฌ ์ธก๋ฉด์—์„œ ๊ฐ•ํ™”ํ•˜๋Š” ๊ฒƒ์ด ์ค‘์š”ํ•˜๋‹ค.

๋ชฉ์ 

  • ๋…ธ๋“œ์— ํ”„๋กœํŒŒ์ผ์„ ์–ด๋–ป๊ฒŒ ์ ์žฌํ•˜๋Š”์ง€ ์˜ˆ์‹œ๋ฅผ ๋ณธ๋‹ค.
  • ํŒŒ๋“œ์— ํ”„๋กœํŒŒ์ผ์„ ์–ด๋–ป๊ฒŒ ๊ฐ•์ œ ์ ์šฉํ•˜๋Š”์ง€ ๋ฐฐ์šด๋‹ค.
  • ํ”„๋กœํŒŒ์ผ์ด ์ ์žฌ๋˜์—ˆ๋Š”์ง€ ํ™•์ธํ•˜๋Š” ๋ฐฉ๋ฒ•์„ ๋ฐฐ์šด๋‹ค.
  • ํ”„๋กœํŒŒ์ผ์„ ์œ„๋ฐ˜ํ•˜๋Š” ๊ฒฝ์šฐ๋ฅผ ์‚ดํŽด๋ณธ๋‹ค.
  • ํ”„๋กœํŒŒ์ผ์„ ์ ์žฌํ•  ์ˆ˜ ์—†์„ ๊ฒฝ์šฐ๋ฅผ ์‚ดํŽด๋ณธ๋‹ค.

์‹œ์ž‘ํ•˜๊ธฐ ์ „์—

๋‹ค์Œ์„ ๋ณด์žฅํ•ด์•ผ ํ•œ๋‹ค.

  1. ์ฟ ๋ฒ„๋„คํ‹ฐ์Šค ๋ฒ„์ „์€ ์ตœ์†Œ 1.4 ์ด๋‹ค. -- ์ฟ ๋ฒ„๋„คํ‹ฐ์Šค v1.4๋ถ€ํ„ฐ AppArmor ์ง€์›์„ ์ถ”๊ฐ€ํ–ˆ๋‹ค. v1.4 ์ด์ „ ์ฟ ๋ฒ„๋„คํ‹ฐ์Šค ์ปดํฌ๋„ŒํŠธ๋Š” ์ƒˆ๋กœ์šด AppArmor ์–ด๋…ธํ…Œ์ด์…˜์„ ์ธ์‹ํ•˜์ง€ ๋ชปํ•˜๊ณ  ์ œ๊ณต๋˜๋Š” AppArmor ์„ค์ •์„ ์กฐ์šฉํžˆ ๋ฌด์‹œํ•  ๊ฒƒ์ด๋‹ค. ํŒŒ๋“œ์—์„œ ์˜ˆ์ƒํ•˜๋Š” ๋ณดํ˜ธ๋ฅผ ๋ฐ›๊ณ  ์žˆ๋Š”์ง€ ํ™•์ธํ•˜๋ ค๋ฉด ํ•ด๋‹น ๋…ธ๋“œ์˜ Kubelet ๋ฒ„์ „์„ ํ™•์ธํ•˜๋Š” ๊ฒƒ์ด ์ค‘์š”ํ•˜๋‹ค.

    $ kubectl get nodes -o=jsonpath=$'{range .items[*]}{@.metadata.name}: {@.status.nodeInfo.kubeletVersion}\n{end}'
    
    gke-test-default-pool-239f5d02-gyn2: v1.4.0
    gke-test-default-pool-239f5d02-x1kf: v1.4.0
    gke-test-default-pool-239f5d02-xwux: v1.4.0
    
  2. AppArmor ์ปค๋„ ๋ชจ๋“ˆ์„ ์‚ฌ์šฉ ๊ฐ€๋Šฅํ•ด์•ผ ํ•œ๋‹ค. -- ๋ฆฌ๋ˆ…์Šค ์ปค๋„์— AppArmor ํ”„๋กœํŒŒ์ผ์„ ๊ฐ•์ œ ์ ์šฉํ•˜๊ธฐ ์œ„ํ•ด AppArmor ์ปค๋„ ๋ชจ๋“ˆ์€ ๋ฐ˜๋“œ์‹œ ์„ค์น˜๋˜์–ด ์žˆ๊ณ  ์‚ฌ์šฉ ๊ฐ€๋Šฅํ•ด์•ผ ํ•œ๋‹ค. ์˜ˆ๋ฅผ ๋“ค์–ด Ubuntu ๋ฐ SUSE ๊ฐ™์€ ๋ฐฐํฌํŒ์€ ๋ชจ๋“ˆ์„ ๊ธฐ๋ณธ๊ฐ’์œผ๋กœ ์ง€์›ํ•˜๊ณ , ๊ทธ ์™ธ ๋งŽ์€ ๋‹ค๋ฅธ ๋ฐฐํฌํŒ๋“ค์€ ์„ ํƒ์ ์œผ๋กœ ์ง€์›ํ•œ๋‹ค. ๋ชจ๋“ˆ์ด ์‚ฌ์šฉ ๊ฐ€๋Šฅํ•œ์ง€ ํ™•์ธํ•˜๋ ค๋ฉด /sys/module/apparmor/parameters/enabled ํŒŒ์ผ์„ ํ™•์ธํ•œ๋‹ค.

    $ cat /sys/module/apparmor/parameters/enabled
    Y
    

    Kubelet(>=v1.4)์ด AppArmor ๊ธฐ๋Šฅ ์ง€์›์„ ํฌํ•จํ•˜์ง€๋งŒ, ์ปค๋„ ๋ชจ๋“ˆ์„ ์‚ฌ์šฉํ•  ์ˆ˜ ์—†์œผ๋ฉด ํŒŒ๋“œ์—์„œ AppArmor ์˜ต์…˜์„ ์‹คํ–‰ํ•˜๋Š” ๊ฒƒ์ด ๊ฑฐ๋ถ€๋œ๋‹ค.

  1. ์ปจํ…Œ์ด๋„ˆ ๋Ÿฐํƒ€์ž„์ด AppArmor์„ ์ง€์›ํ•œ๋‹ค. -- ํ˜„์žฌ ๋ชจ๋“  ์ผ๋ฐ˜์ ์ธ ์ฟ ๋ฒ„๋„คํ‹ฐ์Šค๋ฅผ ์ง€์›ํ•˜๋Š” ๋„์ปค(Docker), CRI-O ๋˜๋Š” containerd ์™€ ๊ฐ™์€ ์ปจํ…Œ์ด๋„ˆ ๋Ÿฐํƒ€์ž„๋“ค์€ AppArmor๋ฅผ ์ง€์›ํ•ด์•ผ ํ•œ๋‹ค. ์ด ๋Ÿฐํƒ€์ž„ ์„ค๋ช…์„œ๋ฅผ ์ฐธ์กฐํ•ด์„œ ํด๋Ÿฌ์Šคํ„ฐ๊ฐ€ AppArmor๋ฅผ ์‚ฌ์šฉํ•˜๊ธฐ ์œ„ํ•œ ์š”๊ตฌ ์‚ฌํ•ญ์„ ์ถฉ์กฑํ•˜๋Š”์ง€ ํ™•์ธํ•ด์•ผ ํ•œ๋‹ค.

  2. ํ”„๋กœํŒŒ์ผ์ด ์ ์žฌ๋˜์–ด ์žˆ๋‹ค. -- AppArmor๋Š” ๊ฐ ์ปจํ…Œ์ด๋„ˆ์™€ ํ•จ๊ป˜ ์‹คํ–‰ํ•ด์•ผ ํ•˜๋Š” AppArmor ํ”„๋กœํŒŒ์ผ์„ ์ง€์ •ํ•˜์—ฌ ํŒŒ๋“œ์— ์ ์šฉํ•œ๋‹ค. ์ปค๋„์— ์ง€์ •ํ•œ ํ”„๋กœํŒŒ์ผ์ด ์ ์žฌ๋˜์ง€ ์•Š์•˜๋‹ค๋ฉด, Kubelet(>= v1.4)์€ ํŒŒ๋“œ๋ฅผ ๊ฑฐ๋ถ€ํ•œ๋‹ค. ํ•ด๋‹น ๋…ธ๋“œ์— ์–ด๋–ค ํ”„๋กœํŒŒ์ผ์ด ์ ์žฌ๋˜์—ˆ๋Š”์ง€๋Š” /sys/kernel/security/apparmor/profiles ํŒŒ์ผ์„ ํ†ตํ•ด ํ™•์ธํ•  ์ˆ˜ ์žˆ๋‹ค. ์˜ˆ๋ฅผ ๋“ค์–ด,

    $ ssh gke-test-default-pool-239f5d02-gyn2 "sudo cat /sys/kernel/security/apparmor/profiles | sort"
    
    apparmor-test-deny-write (enforce)
    apparmor-test-audit-write (enforce)
    docker-default (enforce)
    k8s-nginx (enforce)
    

    ๋…ธ๋“œ์— ํ”„๋กœํŒŒ์ผ์„ ์ ์žฌํ•˜๋Š” ๊ฒƒ์— ๋Œ€ํ•ด ๋” ์ž์„ธํ•œ ๋‚ด์šฉ์€ ํ”„๋กœํŒŒ์ผ๊ณผ ํ•จ๊ป˜ ๋…ธ๋“œ ์„ค์ •ํ•˜๊ธฐ.

AppArmor ์ง€์›์ด ํฌํ•จ๋œ Kubelet (>= v1.4)์ด๋ฉด ์–ด๋–ค ์ „์ œ ์กฐ๊ฑด์ด ์ถฉ์กฑ๋˜์ง€ ์•Š์œผ๋ฉด AppArmor์™€ ํ•จ๊ป˜ํ•œ ํŒŒ๋“œ๋ฅผ ๊ฑฐ๋ถ€ํ•œ๋‹ค. ๋…ธ๋“œ ์ƒ์— AppArmor ์ง€์› ์—ฌ๋ถ€๋Š” ๋…ธ๋“œ ์ค€๋น„ ์กฐ๊ฑด ๋ฉ”์‹œ์ง€๋ฅผ ํ™•์ธํ•˜์—ฌ(์ดํ›„ ๋ฆด๋ฆฌ์Šค์—์„œ๋Š” ์‚ญ์ œ๋  ๊ฒƒ ๊ฐ™์ง€๋งŒ) ๊ฒ€์ฆํ•  ์ˆ˜ ์žˆ๋‹ค.

kubectl get nodes -o=jsonpath='{range .items[*]}{@.metadata.name}: {.status.conditions[?(@.reason=="KubeletReady")].message}{"\n"}{end}'
gke-test-default-pool-239f5d02-gyn2: kubelet is posting ready status. AppArmor enabled
gke-test-default-pool-239f5d02-x1kf: kubelet is posting ready status. AppArmor enabled
gke-test-default-pool-239f5d02-xwux: kubelet is posting ready status. AppArmor enabled

ํŒŒ๋“œ ๋ณด์•ˆ ๊ฐ•ํ™”ํ•˜๊ธฐ

AppArmor ํ”„๋กœํŒŒ์ผ์€ ์ปจํ…Œ์ด๋„ˆ๋งˆ๋‹ค ์ง€์ •๋œ๋‹ค. ํ•จ๊ป˜ ์‹คํ–‰ํ•  ํŒŒ๋“œ ์ปจํ…Œ์ด๋„ˆ์— AppArmor ํ”„๋กœํŒŒ์ผ์„ ์ง€์ •ํ•˜๋ ค๋ฉด ํŒŒ๋“œ์˜ ๋ฉ”ํƒ€๋ฐ์ดํ„ฐ์— ์–ด๋…ธํ…Œ์ด์…˜์„ ์ถ”๊ฐ€ํ•œ๋‹ค.

container.apparmor.security.beta.kubernetes.io/<container_name>: <profile_ref>

<container_name>์€ ํ”„๋กœํŒŒ์ผ์„ ์ ์šฉํ•˜๋Š” ์ปจํ…Œ์ด๋„ˆ ์ด๋ฆ„์ด๊ณ , <profile_ref>๋Š” ์ ์šฉํ•  ํ”„๋กœํŒŒ์ผ์„ ์ง€์ •ํ•œ๋‹ค. profile_ref๋Š” ๋‹ค์Œ ์ค‘์— ํ•˜๋‚˜์ด๋‹ค.

  • ๋Ÿฐํƒ€์ž„์˜ ๊ธฐ๋ณธ ํ”„๋กœํŒŒ์ผ์„ ์ ์šฉํ•˜๊ธฐ ์œ„ํ•œ runtime/default
  • <profile_name>๋กœ ์ด๋ฆ„ํ•œ ํ˜ธ์ŠคํŠธ์— ์ ์žฌ๋˜๋Š” ํ”„๋กœํŒŒ์ผ์„ ์ ์šฉํ•˜๊ธฐ ์œ„ํ•œ localhost/<profile_name>
  • ์ ์žฌํ•  ํ”„๋กœํŒŒ์ผ์ด ์—†์Œ์„ ๋‚˜ํƒ€๋‚ด๋Š” unconfined

์–ด๋…ธํ…Œ์ด์…˜๊ณผ ํ”„๋กœํŒŒ์ผ ์ด๋ฆ„ ํ˜•์‹์˜ ์ž์„ธํ•œ ๋‚ด์šฉ์€ API ์ฐธ์กฐ๋ฅผ ์‚ดํŽด๋ณธ๋‹ค.

์ฟ ๋ฒ„๋„คํ‹ฐ์Šค AppArmor ์˜ ์ž‘๋™ ์ˆœ์„œ๋Š” ๋ชจ๋“  ์„ ํ–‰ ์กฐ๊ฑด์ด ์ถฉ์กฑ๋˜์—ˆ๋Š”์ง€ ํ™•์ธํ•˜๊ณ , ์ ์šฉ์„ ์œ„ํ•ด ์„ ํƒํ•œ ํ”„๋กœํŒŒ์ผ์„ ์ปจํ…Œ์ด๋„ˆ ๋Ÿฐํƒ€์ž„์œผ๋กœ ์ „๋‹ฌํ•˜์—ฌ ์ด๋ฃจ์–ด์ง„๋‹ค. ๋งŒ์•ฝ ์„ ํ–‰ ์กฐ๊ฑด์ด ์ถฉ์กฑ๋˜์ง€ ์•Š์œผ๋ฉด ํŒŒ๋“œ๋Š” ๊ฑฐ๋ถ€๋˜๊ณ  ์‹คํ–‰๋˜์ง€ ์•Š๋Š”๋‹ค.

ํ”„๋กœํŒŒ์ผ์ด ์ ์šฉ๋˜์—ˆ๋Š”์ง€ ํ™•์ธํ•˜๊ธฐ ์œ„ํ•ด, ์ปจํ…Œ์ด๋„ˆ ์ƒ์„ฑ ์ด๋ฒคํŠธ์— ๋‚˜์—ด๋œ AppArmor ๋ณด์•ˆ ์˜ต์…˜์„ ์ฐพ์•„ ๋ณผ ์ˆ˜ ์žˆ๋‹ค.

kubectl get events | grep Created
22s        22s         1         hello-apparmor     Pod       spec.containers{hello}   Normal    Created     {kubelet e2e-test-stclair-node-pool-31nt}   Created container with docker id 269a53b202d3; Security:[seccomp=unconfined apparmor=k8s-apparmor-example-deny-write]

์ปจํ…Œ์ด๋„ˆ์˜ ๋ฃจํŠธ ํ”„๋กœ์„ธ์Šค๊ฐ€ ์˜ฌ๋ฐ”๋ฅธ ํ”„๋กœํŒŒ์ผ๋กœ ์‹คํ–‰๋˜๋Š”์ง€๋Š” proc attr์„ ํ™•์ธํ•˜์—ฌ ์ง์ ‘ ๊ฒ€์ฆํ•  ์ˆ˜ ์žˆ๋‹ค.

kubectl exec <pod_name> -- cat /proc/1/attr/current
k8s-apparmor-example-deny-write (enforce)

์˜ˆ์‹œ

์ด ์˜ˆ์‹œ๋Š” AppArmor๋ฅผ ์ง€์›ํ•˜๋Š” ํด๋Ÿฌ์Šคํ„ฐ๋ฅผ ์ด๋ฏธ ๊ตฌ์„ฑํ•˜์˜€๋‹ค๊ณ  ๊ฐ€์ •ํ•œ๋‹ค.

๋จผ์ € ๋…ธ๋“œ์—์„œ ์‚ฌ์šฉํ•˜๋ ค๋Š” ํ”„๋กœํŒŒ์ผ์„ ์ ์žฌํ•ด์•ผ ํ•œ๋‹ค. ์‚ฌ์šฉํ•  ํ”„๋กœํŒŒ์ผ์€ ํŒŒ์ผ ์“ฐ๊ธฐ๋ฅผ ๊ฑฐ๋ถ€ํ•œ๋‹ค.

#include <tunables/global>

profile k8s-apparmor-example-deny-write flags=(attach_disconnected) {
  #include <abstractions/base>

  file,

  # Deny all file writes.
  deny /** w,
}

ํŒŒ๋“œ๋ฅผ ์–ธ์ œ ์Šค์ผ€์ค„ํ• ์ง€ ์•Œ์ง€ ๋ชปํ•˜๋ฏ€๋กœ ๋ชจ๋“  ๋…ธ๋“œ์— ํ”„๋กœํŒŒ์ผ์„ ์ ์žฌํ•ด์•ผ ํ•œ๋‹ค. ์ด ์˜ˆ์‹œ์—์„œ๋Š” SSH๋ฅผ ์ด์šฉํ•˜์—ฌ ํ”„๋กœํŒŒ์ผ์„ ์„ค์น˜ํ•  ๊ฒƒ์ด๋‚˜ ๋‹ค๋ฅธ ๋ฐฉ๋ฒ•์€ ํ”„๋กœํŒŒ์ผ๊ณผ ํ•จ๊ป˜ ๋…ธ๋“œ ์„ค์ •ํ•˜๊ธฐ์—์„œ ๋…ผ์˜ํ•œ๋‹ค.

NODES=(
    # The SSH-accessible domain names of your nodes
    gke-test-default-pool-239f5d02-gyn2.us-central1-a.my-k8s
    gke-test-default-pool-239f5d02-x1kf.us-central1-a.my-k8s
    gke-test-default-pool-239f5d02-xwux.us-central1-a.my-k8s)
for NODE in ${NODES[*]}; do ssh $NODE 'sudo apparmor_parser -q <<EOF
#include <tunables/global>

profile k8s-apparmor-example-deny-write flags=(attach_disconnected) {
  #include <abstractions/base>

  file,

  # Deny all file writes.
  deny /** w,
}
EOF'
done

๋‹ค์Œ์œผ๋กœ ์“ฐ๊ธฐ ๊ธˆ์ง€ ํ”„๋กœํŒŒ์ผ๋œ "Hello AppArmor" ํŒŒ๋“œ๋ฅผ ์‹คํ–‰ํ•œ๋‹ค.

apiVersion: v1
kind: Pod
metadata:
  name: hello-apparmor
  annotations:
    # ์ฟ ๋ฒ„๋„คํ‹ฐ์Šค์— 'k8s-apparmor-example-deny-write' AppArmor ํ”„๋กœํŒŒ์ผ์„ ์ ์šฉํ•จ์„ ์•Œ๋ฆฐ๋‹ค.
    # ์žŠ์ง€ ๋ง ๊ฒƒ์€ ์ฟ ๋ฒ„๋„คํ‹ฐ์Šค ๋…ธ๋“œ์—์„œ ์‹คํ–‰ ์ค‘์ธ ๋ฒ„์ „์ด 1.4 ์ด์ƒ์ด ์•„๋‹Œ ๊ฒฝ์šฐ์—๋Š” ์ด ์„ค์ •์€ ๋ฌด์‹œ๋œ๋‹ค๋Š” ๊ฒƒ์ด๋‹ค.
    container.apparmor.security.beta.kubernetes.io/hello: localhost/k8s-apparmor-example-deny-write
spec:
  containers:
  - name: hello
    image: busybox:1.28
    command: [ "sh", "-c", "echo 'Hello AppArmor!' && sleep 1h" ]
kubectl create -f ./hello-apparmor.yaml

ํŒŒ๋“œ ์ด๋ฒคํŠธ๋ฅผ ์‚ดํŽด๋ณด๋ฉด, 'k8s-apparmor-example-deny-write' AppArmor ํ”„๋กœํŒŒ์ผ๋กœ ์ƒ์„ฑ๋œ ํŒŒ๋“œ ์ปจํ…Œ์ด๋„ˆ๋ฅผ ํ™•์ธํ•  ์ˆ˜ ์žˆ๋‹ค.

kubectl get events | grep hello-apparmor
14s        14s         1         hello-apparmor   Pod                                Normal    Scheduled   {default-scheduler }                           Successfully assigned hello-apparmor to gke-test-default-pool-239f5d02-gyn2
14s        14s         1         hello-apparmor   Pod       spec.containers{hello}   Normal    Pulling     {kubelet gke-test-default-pool-239f5d02-gyn2}   pulling image "busybox"
13s        13s         1         hello-apparmor   Pod       spec.containers{hello}   Normal    Pulled      {kubelet gke-test-default-pool-239f5d02-gyn2}   Successfully pulled image "busybox"
13s        13s         1         hello-apparmor   Pod       spec.containers{hello}   Normal    Created     {kubelet gke-test-default-pool-239f5d02-gyn2}   Created container with docker id 06b6cd1c0989; Security:[seccomp=unconfined apparmor=k8s-apparmor-example-deny-write]
13s        13s         1         hello-apparmor   Pod       spec.containers{hello}   Normal    Started     {kubelet gke-test-default-pool-239f5d02-gyn2}   Started container with docker id 06b6cd1c0989

proc attr์„ ํ™•์ธํ•˜์—ฌ ์ปจํ…Œ์ด๋„ˆ๊ฐ€ ์‹ค์ œ๋กœ ํ•ด๋‹น ํ”„๋กœํŒŒ์ผ๋กœ ์‹คํ–‰ ์ค‘์ธ์ง€ ํ™•์ธํ•  ์ˆ˜ ์žˆ๋‹ค.

kubectl exec hello-apparmor -- cat /proc/1/attr/current
k8s-apparmor-example-deny-write (enforce)

๋งˆ์ง€๋ง‰์œผ๋กœ ํŒŒ์ผ ์“ฐ๊ธฐ๋ฅผ ํ†ตํ•ด ํ”„๋กœํŒŒ์ผ์„ ์œ„๋ฐ˜ํ•˜๋ฉด ์–ด๋–ป๊ฒŒ ๋˜๋Š”์ง€ ํ™•์ธํ•  ์ˆ˜ ์žˆ๋‹ค.

kubectl exec hello-apparmor -- touch /tmp/test
touch: /tmp/test: Permission denied
error: error executing remote command: command terminated with non-zero exit code: Error executing in Docker Container: 1

์ด์ œ ์ •๋ฆฌํ•˜๋ฉด์„œ, ์ ์žฌ๋˜์ง€ ์•Š์€ ํ”„๋กœํŒŒ์ผ์„ ์ง€์ •ํ•˜๋ฉด ์–ด๋–ป๊ฒŒ ๋˜๋Š”์ง€ ์‚ดํŽด๋ณธ๋‹ค.

kubectl create -f /dev/stdin <<EOF
apiVersion: v1
kind: Pod
metadata:
  name: hello-apparmor-2
  annotations:
    container.apparmor.security.beta.kubernetes.io/hello: localhost/k8s-apparmor-example-allow-write
spec:
  containers:
  - name: hello
    image: busybox:1.28
    command: [ "sh", "-c", "echo 'Hello AppArmor!' && sleep 1h" ]
EOF
pod/hello-apparmor-2 created
kubectl describe pod hello-apparmor-2
Name:          hello-apparmor-2
Namespace:     default
Node:          gke-test-default-pool-239f5d02-x1kf/
Start Time:    Tue, 30 Aug 2016 17:58:56 -0700
Labels:        <none>
Annotations:   container.apparmor.security.beta.kubernetes.io/hello=localhost/k8s-apparmor-example-allow-write
Status:        Pending
Reason:        AppArmor
Message:       Pod Cannot enforce AppArmor: profile "k8s-apparmor-example-allow-write" is not loaded
IP:
Controllers:   <none>
Containers:
  hello:
    Container ID:
    Image:     busybox
    Image ID:
    Port:
    Command:
      sh
      -c
      echo 'Hello AppArmor!' && sleep 1h
    State:              Waiting
      Reason:           Blocked
    Ready:              False
    Restart Count:      0
    Environment:        <none>
    Mounts:
      /var/run/secrets/kubernetes.io/serviceaccount from default-token-dnz7v (ro)
Conditions:
  Type          Status
  Initialized   True
  Ready         False
  PodScheduled  True
Volumes:
  default-token-dnz7v:
    Type:    Secret (a volume populated by a Secret)
    SecretName:    default-token-dnz7v
    Optional:   false
QoS Class:      BestEffort
Node-Selectors: <none>
Tolerations:    <none>
Events:
  FirstSeen    LastSeen    Count    From                        SubobjectPath    Type        Reason        Message
  ---------    --------    -----    ----                        -------------    --------    ------        -------
  23s          23s         1        {default-scheduler }                         Normal      Scheduled     Successfully assigned hello-apparmor-2 to e2e-test-stclair-minion-group-t1f5
  23s          23s         1        {kubelet e2e-test-stclair-node-pool-t1f5}             Warning        AppArmor    Cannot enforce AppArmor: profile "k8s-apparmor-example-allow-write" is not loaded

ํŒŒ๋“œ ์ƒํƒœ๋Š” Pending์ด๋ฉฐ, ์˜ค๋ฅ˜ ๋ฉ”์‹œ์ง€๋Š” Pod Cannot enforce AppArmor: profile "k8s-apparmor-example-allow-write" is not loaded์ด๋‹ค. ์ด๋ฒคํŠธ๋„ ๋™์ผํ•œ ๋ฉ”์‹œ์ง€๋กœ ๊ธฐ๋ก๋˜์—ˆ๋‹ค.

๊ด€๋ฆฌ

ํ”„๋กœํŒŒ์ผ๊ณผ ํ•จ๊ป˜ ๋…ธ๋“œ ์„ค์ •ํ•˜๊ธฐ

ํ˜„์žฌ ์ฟ ๋ฒ„๋„คํ‹ฐ์Šค๋Š” AppArmor ํ”„๋กœํŒŒ์ผ์„ ๋…ธ๋“œ์— ์ ์žฌํ•˜๊ธฐ ์œ„ํ•œ ๋„ค์ดํ‹ฐ๋ธŒ ๋ฉ”์ปค๋‹ˆ์ฆ˜์„ ์ œ๊ณตํ•˜์ง€ ์•Š๋Š”๋‹ค. ํ”„๋กœํŒŒ์ผ์„ ์„ค์ •ํ•˜๋Š” ์—ฌ๋Ÿฌ ๋ฐฉ๋ฒ•์ด ์žˆ๋‹ค. ์˜ˆ๋ฅผ ๋“ค๋ฉด ๋‹ค์Œ๊ณผ ๊ฐ™๋‹ค.

  • ๊ฐ ๋…ธ๋“œ์—์„œ ํŒŒ๋“œ๋ฅผ ์‹คํ–‰ํ•˜๋Š” ๋ฐ๋ชฌ์…‹์„ ํ†ตํ•ด์„œ ์˜ฌ๋ฐ”๋ฅธ ํ”„๋กœํŒŒ์ผ์ด ์ ์žฌ๋˜์—ˆ๋Š”์ง€ ํ™•์ธํ•œ๋‹ค. ์˜ˆ์‹œ ๊ตฌํ˜„์€ ์—ฌ๊ธฐ์—์„œ ์ฐพ์•„๋ณผ ์ˆ˜ ์žˆ๋‹ค.
  • ๋…ธ๋“œ ์ดˆ๊ธฐํ™” ์‹œ๊ฐ„์— ๋…ธ๋“œ ์ดˆ๊ธฐํ™” ์Šคํฌ๋ฆฝํŠธ(์˜ˆ๋ฅผ ๋“ค์–ด Salt, Ansible ๋“ฑ)๋‚˜ ์ด๋ฏธ์ง€๋ฅผ ์ด์šฉ
  • ์˜ˆ์‹œ์—์„œ ๋ณด์—ฌ์ค€ ๊ฒƒ์ฒ˜๋Ÿผ, ํ”„๋กœํŒŒ์ผ์„ ๊ฐ ๋…ธ๋“œ์— ๋ณต์‚ฌํ•˜๊ณ  SSH๋ฅผ ํ†ตํ•ด ์ ์žฌํ•œ๋‹ค.

์Šค์ผ€์ค„๋Ÿฌ๋Š” ์–ด๋–ค ํ”„๋กœํŒŒ์ผ์ด ์–ด๋–ค ๋…ธ๋“œ์— ์ ์žฌ๋˜๋Š”์ง€ ๊ณ ๋ คํ•˜์ง€ ์•Š์œผ๋‹ˆ, ํ”„๋กœํŒŒ์ผ ์ „์ฒด ์ง‘ํ•ฉ์ด ๋ชจ๋“  ๋…ธ๋“œ์— ์ ์žฌ๋˜์–ด์•ผ ํ•œ๋‹ค. ๋Œ€์•ˆ์ ์ธ ๋ฐฉ๋ฒ•์€ ๊ฐ ํ”„๋กœํŒŒ์ผ(ํ˜น์€ ํ”„๋กœํŒŒ์ผ์˜ ํด๋ž˜์Šค)์„ ์œ„ํ•œ ๋…ธ๋“œ ๋ ˆ์ด๋ธ”์„ ๋…ธ๋“œ์— ์ถ”๊ฐ€ํ•˜๊ณ , ๋…ธ๋“œ ์…€๋ ‰ํ„ฐ๋ฅผ ์ด์šฉํ•˜์—ฌ ํŒŒ๋“œ๊ฐ€ ํ•„์š”ํ•œ ํ”„๋กœํŒŒ์ผ์ด ์žˆ๋Š” ๋…ธ๋“œ์—์„œ ์‹คํ–‰๋˜๋„๋ก ํ•œ๋‹ค.

AppArmor ๋น„ํ™œ์„ฑํ™”

ํด๋Ÿฌ์Šคํ„ฐ์—์„œ AppArmor๋ฅผ ์‚ฌ์šฉํ•˜์ง€ ์•Š์œผ๋ ค๋ฉด, ์ปค๋งจ๋“œ๋ผ์ธ ํ”Œ๋ž˜๊ทธ๋กœ ๋น„ํ™œ์„ฑํ™” ํ•  ์ˆ˜ ์žˆ๋‹ค.

--feature-gates=AppArmor=false

๋น„ํ™œ์„ฑํ™”๋˜๋ฉด, AppArmor ํ”„๋กœํŒŒ์ผ์„ ํฌํ•จํ•œ ํŒŒ๋“œ๋Š” "Forbidden" ์˜ค๋ฅ˜๋กœ ๊ฒ€์ฆ ์‹คํŒจํ•œ๋‹ค.

ํ”„๋กœํŒŒ์ผ ์ œ์ž‘

AppArmor ํ”„๋กœํŒŒ์ผ์„ ๋งŒ๋“ค๊ณ  ์˜ฌ๋ฐ”๋ฅด๊ฒŒ ์ง€์ •ํ•˜๋Š” ๊ฒƒ์€ ๋งค์šฐ ๊นŒ๋‹ค๋กœ์šธ ์ˆ˜ ์žˆ๋‹ค. ๋‹คํ–‰ํžˆ ์ด ์ž‘์—…์— ๋„์›€ ๋˜๋Š” ๋„๊ตฌ๊ฐ€ ์žˆ๋‹ค.

  • aa-genprof์™€ aa-logprof๋Š” ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ํ™œ๋™๊ณผ ๋กœ๊ทธ์™€ ์ˆ˜ํ–‰์— ํ•„์š”ํ•œ ํ–‰๋™์„ ๋ชจ๋‹ˆํ„ฐ๋งํ•˜์—ฌ ์ผ๋ฐ˜ ํ”„๋กœํŒŒ์ผ ๊ทœ์น™์„ ์ƒ์„ฑํ•œ๋‹ค. ์ž์„ธํ•œ ์‚ฌ์šฉ๋ฐฉ๋ฒ•์€ AppArmor ๋ฌธ์„œ์—์„œ ์ œ๊ณตํ•œ๋‹ค.
  • bane์€ ๋‹จ์ˆœํ™”๋œ ํ”„๋กœํŒŒ์ผ ์–ธ์–ด๋ฅผ ์ด์šฉํ•˜๋Š” ๋„์ปค๋ฅผ ์œ„ํ•œ AppArmor ํ”„๋กœํŒŒ์ผ ์ƒ์„ฑ๊ธฐ์ด๋‹ค.

AppArmor ๋ฌธ์ œ๋ฅผ ๋””๋ฒ„๊น…ํ•˜๊ธฐ ์œ„ํ•ด์„œ ๊ฑฐ๋ถ€๋œ ๊ฒƒ์œผ๋กœ ๋ณด์ด๋Š” ์‹œ์Šคํ…œ ๋กœ๊ทธ๋ฅผ ํ™•์ธํ•  ์ˆ˜ ์žˆ๋‹ค. AppArmor ๋กœ๊ทธ๋Š” dmesg์—์„œ ๋ณด์ด๋ฉฐ, ์˜ค๋ฅ˜๋Š” ๋ณดํ†ต ์‹œ์Šคํ…œ ๋กœ๊ทธ๋‚˜ journalctl์—์„œ ๋ณผ ์ˆ˜ ์žˆ๋‹ค. ๋” ๋งŽ์€ ์ •๋ณด๋Š” AppArmor ์‹คํŒจ์—์„œ ์ œ๊ณตํ•œ๋‹ค.

API ์ฐธ์กฐ

ํŒŒ๋“œ ์–ด๋…ธํ…Œ์ด์…˜

์ปจํ…Œ์ด๋„ˆ๋ฅผ ์‹คํ–‰ํ•  ํ”„๋กœํŒŒ์ผ์„ ์ง€์ •ํ•œ๋‹ค.

  • ํ‚ค: container.apparmor.security.beta.kubernetes.io/<container_name> <container_name>๋Š” ํŒŒ๋“œ ๋‚ด์— ์ปจํ…Œ์ด๋„ˆ ์ด๋ฆ„๊ณผ ์ผ์น˜ํ•œ๋‹ค. ๋ถ„๋ฆฌ๋œ ํ”„๋กœํŒŒ์ผ์€ ํŒŒ๋“œ ๋‚ด์— ๊ฐ ์ปจํ…Œ์ด๋„ˆ๋กœ ์ง€์ •ํ•  ์ˆ˜ ์žˆ๋‹ค.
  • ๊ฐ’: ์•„๋ž˜ ๊ธฐ์ˆ ๋œ ํ”„๋กœํŒŒ์ผ ์ฐธ์กฐ

ํ”„๋กœํŒŒ์ผ ์ฐธ์กฐ

  • runtime/default: ๊ธฐ๋ณธ ๋Ÿฐํƒ€์ž„ ํ”„๋กœํŒŒ์ผ์„ ์ฐธ์กฐํ•œ๋‹ค.
    • (๊ธฐ๋ณธ ํŒŒ๋“œ์‹œํ๋ฆฌํ‹ฐํด๋ฆฌ์‹œ ์—†์ด) ํ”„๋กœํŒŒ์ผ์„ ์ง€์ •ํ•˜์ง€ ์•Š๊ณ  AppArmor๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ๊ณผ ๋™๋“ฑํ•˜๋‹ค.
    • ์‹ค์ œ๋กœ๋Š”, ๋งŽ์€ ์ปจํ…Œ์ด๋„ˆ ๋Ÿฐํƒ€์ž„์€ ๋™์ผํ•œ OCI ๊ธฐ๋ณธ ํ”„๋กœํŒŒ์ผ์„ ์‚ฌ์šฉํ•˜๋ฉฐ, ์ด๋Š” https://github.com/containers/common/blob/main/pkg/apparmor/apparmor_linux_template.go ์— ์ •์˜๋˜์–ด ์žˆ๋‹ค.
  • localhost/<profile_name>: ๋…ธ๋“œ(localhost)์— ์ ์žฌ๋œ ํ”„๋กœํŒŒ์ผ์„ ์ด๋ฆ„์œผ๋กœ ์ฐธ์กฐํ•œ๋‹ค.
  • unconfined: ์ด๊ฒƒ์€ ์ปจํ…Œ์ด๋„ˆ์—์„œ AppArmor๋ฅผ ํšจ๊ณผ์ ์œผ๋กœ ๋น„ํ™œ์„ฑ์‹œํ‚จ๋‹ค.

๋‹ค๋ฅธ ์–ด๋–ค ํ”„๋กœํŒŒ์ผ ์ฐธ์กฐ ํ˜•์‹๋„ ์œ ํšจํ•˜์ง€ ์•Š๋‹ค.

๋‹ค์Œ ๋‚ด์šฉ

์ฐธ๊ณ  ์ž๋ฃŒ

์ตœ์ข… ์ˆ˜์ • March 22, 2023 at 3:39 PM PST: [ko] Update outdated files in dev-1.26-ko.1 (M165-M173,M189-M196) (2c7b7ef130)