Привет всем, в продолжении CKA сегодня получил следующий сертификат CKS - Certified Kubernetes Security Specialist (ID Number: LF-lq76nh25g0) и хотел бы поделиться рекомендациями для успешной сдачи экзамена. Не претендую на истину в последней инстанции, а лишь делюсь личным опытом и впечатлениями. Возможно кому-то будет полезно.
Казалось бы, у нас нет ничего особого нового, мы просто поменяли контекст с общего на безопасность, и если CKA был относительно не сложным экзаменом, то вот CKS был прямо испытанием. Я смог пройти его только со второй попытки, в первой набрал 64% из необходимых 67%, вторая попытка была успешная и завершилась с результатом 83%.
И так, основная проблема, как бы это странно не звучало - время, а точнее его не хватка. Времени сильно не хватает. Напомню, что продолжительность экзамена 120 минут, вам дается 16-18 вопросов, лично у меня было 16, т.е. в среднем 7,5 минуты на вопрос. Но в отличие от CKA здесь задачи более объемные и как правило требуют больше времени на решение.
Теория
Здесь не будет ничего эдакого, я купил курс от kodekloud от уже известного нам по первой статье Mumshad Mannambeth. На этот раз на Udemy я не брал никакие курсы.
А так же просмотрел курс на youtube
Практика
Несмотря на наличие mock экзаменов в теоретическом курсе, практики будет явно недостаточно.
Для получения практики я использовал следующие курсы/лабы:
https://kodekloud.com/courses/kubernetes-challenges/
https://kodekloud.com/courses/cks-challenges
Напоминаю, как показала практика общения в slack канале killer.sh, не все люди знают, что при покупке экзамена, вы получаете две полноценные сессии у killer.sh. Они очень сильно отличаются от бесплатных заданий. Поэтому я очень рекомендую пройти их и разобрать непонятные моменты.
Ссылка на эмулятор будет доступна на странице самого экзамена:

Не обращайте внимание на название экзамена, после получения сертификата ссылка на эмулятор пропадает, но принцип будет тот же. Сама сессия представляет окружение максимально приближенное к реальному, где вам дается 22 вопроса и 36 часов, т.е. окружение будет доступно в течение 36 часов с момента его создания. Для каждого экзамена доступно две сессии. Если нужна будет еще дополнительная сессия, то придется покупать отдельно. Стоимость каждой дополнительной сессии - 10$.

Настоятельно рекомендую пройти эти сессии, в спокойной обстановке, когда никто не отвлекает и не мешает, у меня была возможность только на выходных. Так же в эмуляторе есть возможность посмотреть правильные ответы, но я советую воспользоваться этой возможностью только в крайнем случае, например, невозможности решить задачу самостоятельно и/или с помощью google.
Так как на экзамене можно использовать только несколько сторонних сайтов, как правило это документация к k8s, falco, etcd, то во время сессий я так же настоятельно советую открыть в веб проводнике https://kubernetes.io/docs/ и весь поиск производить только на самом сайте. Напоминаю, во время экзамена нельзя пользоваться поисковиками, даже если ссылка будет вести на разрешенный сайт. Это поможет привыкнуть к окружению, которое будет на реальном экзамене.
При подготовке практической части я использовал окружения от kodekloud, т.н. playgrounds


Ничего выдающегося, но экономит очень много времени и сил, когда вам надо быстро проверить какую то задачу.
Подготовка к экзамену
Ничем не отличается от CKA. Все тоже самое, как я описывал в первой статье. Все также просят показать уши на камеру и кто у вас сидит под столом )))
Экзамен
Ничем не отличается от CKA, естественно кроме самих вопросов.
Tips & tricks
Поделюсь советами, которые помогут более эффективно сдать экзамен.
Будьте особо внимательны к вопросам, которые относятся к изменениям в kube apiserver и/или etcd. Если в результате ваших изменений вы получите не работающий kubeapi server/etcd, то все задачи, которые относились к этому кластеру - будут считаться не решенными. Что приведет к большой потери баллов. Напомню, что проходной бал - 67%.
Если вас просят запустить pod c определенным apparmor profile, то обращайте внимание на какой ноде необходимо производить запуск, так как профиль привязан к ноде.
Если профиль необходимо применить, например, к deployment, то обращайте внимание в какой именно блок metadata вы добавляете соответствующую аннотацию. Аннотацию необходимо добавлять в
spec.template.metadata.annotations
apiVersion: apps/v1
kind: Deployment
metadata:
annotations:
# неправильно
container.apparmor.security.beta.kubernetes.io/nginx: localhost/deny-write
name: nginx-deployment
labels:
app: nginx
spec:
replicas: 3
selector:
matchLabels:
app: nginx
template:
metadata:
labels:
app: nginx
annotations:
# а так правильно
container.apparmor.security.beta.kubernetes.io/nginx: localhost/deny-write
spec:
containers:
- name: nginx
image: nginx:1.14.2
ports:
- containerPort: 80
Так же не забываем, что в аннотации мы указываем имя контейнера, а не пода
Если в задании требуется сохранить вывод в файл, то скорее всего это надо делать на student node (изначальная нода), и путь уже будет существовать, если такого пути нет, то скорее всего вы делаете что-то не так. Как вариант, вы забыли вернуться на изначальный хост. Аналогично и с ресурсами, если в задании сказано что ns уже создан, а вы видите что его нет, скорее всего вы забыли поменять контекст либо не вышли с master/worker node предыдущего кластера. Всего на экзамене 5 или 6 кластеров.
Некоторые задания можно выполнять только на master/worker нодах, например там будут установлены kube-bench/trivy и т.п. рода утилиты. Обычно об этом явно говорится в задании, но не всегда. Например, если вам надо настроить аудит, то это можно сделать только на мастер ноде, но об этом не будут явно говорить. Для того чтобы быстро подключиться, делаем вывод нод
k get node
после смены контекста и затемssh master-node-name
илиssh worker-node-name
Минимизируйте использование сторонних сайтов с документацией. Так как сама среда работает не особо быстро, а многие hot keys, например, поиск текста на странице не работают вообще, то поиск будет забирать у вас очень много времени, которого катастрофически не хватает.
Если вас просят поменять или задать определенные параметры в kube apiserver или etcd. Используйте для этого уже существующие контейнеры, например, нас попросили установить минимальную версию tls в kube apiserver 1.3, то для этого достаточно выполнить такую команду
$ k exec -it -n kube-system kube-apiserver-controlplane -- kube-apiserver --help | grep tls-min
--tls-min-version string Minimum TLS version supported. Possible values: VersionTLS10, VersionTLS11, VersionTLS12, VersionTLS13
$ k exec -it -n kube-system kube-apiserver-controlplane -- kube-apiserver --help | grep cipher
--tls-cipher-suites strings Comma-separated list of cipher suites for the server. If omitted, the default Go cipher suites will be used.
Мы сразу видим точное название параметра и возможные значения. Список шифров в случае с --tls-cipher-suites
всегда указывается в задании. Перезагрузка etcd у меня занимала 2-3 минуты, следует это учитывать
$ k exec -it -n kube-system etcd-controlplane -- etcd --help | grep cipher
--cipher-suites ''
Comma-separated list of supported TLS cipher suites between client/server and peers (empty will be auto-populated by Go).
Сэкономить еще немного времени так же поможет
kubectl explain
Например, вас попросили добавитьreadOnlyRootFilesystem
, но вы не помните точного написание и где именно надо указывать - используйтеkubectl explain
в сочетании с ключом--recursive=true
$ k explain pod.spec.containers --recursive=true | grep -i rootfilesystem -C10
resources <Object>
limits <map[string]string>
requests <map[string]string>
securityContext <Object>
allowPrivilegeEscalation <boolean>
capabilities <Object>
add <[]string>
drop <[]string>
privileged <boolean>
procMount <string>
readOnlyRootFilesystem <boolean>
runAsGroup <integer>
runAsNonRoot <boolean>
runAsUser <integer>
seLinuxOptions <Object>
level <string>
role <string>
type <string>
user <string>
seccompProfile <Object>
localhostProfile <string>
Задания относящиеся к falco, часто могут быть решены с помощью sysdig. Например ваc просят сохранить логи в определенном формате для определенного контейнера в определенный файл. Если настраивать falco, то это потребует много времени, в отличие от sysdig
$ sysdig -M 120 -p "%evt.time, %user.name %proc.name" container.id=abcdef123
И мы снова можем сэкономить время, не обращаясь к документации falco, если вы не помните имя переменной
$ sysdig --list | grep time
$ sysdig --list | grep container
$ sysdig --list | grep proc
Аналогичные ключи есть и у команды falco. Если вам необходимо изменить существующее правило и добавить новые поля, а sysdig не доступен. В моем случае, в первый раз sysdig был не установлен в системе и я ставил его через apt, но в результате получил не работающую утилиту, ошибка была связано с неверными модулями для ядра, а времени разбираться просто не было.
Так же в моем случае sysdig работал только с фильтром container.name
, а с container.id
ничего не выдавал
В задании c ImagePolicyWebhook вам предлагают для проверки корректности настройки файл с ресурсом, в моем случае это был
ReplicationController
, который немного сбивает с толку, по крайней мере меня. Так как по условию вам говорится, что поды не должны создаваться, но при этом самReplicationController
создается успешно. Первый раз меня это сбило с толку и я потратил лишние минут 5 на перепроверку всех параметров, затем просто создал pod c тегом latest и увидел в терминале, что мой запрос был заблокированВ заданиях с сетевыми политиками не забывайте про явную необходимость указывать namespace, если вас просят предоставить доступ к поду с любого namespace
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: allow-app-label
namespace: db
spec:
podSelector:
matchLabels:
type: db
policyTypes:
- Ingress
ingress:
- from:
- namespaceSelector: {}
podSelector:
matchLabels:
type: app
Таким образом мы разрешили входящий трафик в namespace=db
для подов из любого namespace c меткой type=app
Так же обратите внимание на следующие примеры
- from:
- namespaceSelector:
matchLabels:
kubernetes.io/metadata.name: frontend
podSelector:
matchLabels:
type: nodejs
- from:
- namespaceSelector:
matchLabels:
kubernetes.io/metadata.name: frontend
- podSelector:
matchLabels:
type: nodejs
у этих правил будет абсолютно разный эффект, хотя отличие всего в один символ.
В первом случае мы разрешаем доступ только подам с меткой type=nodejs
и только с namespace=frontend
.
Во втором случае мы разрешаем доступ любым подам с namespace=frontend
.
После создание сетевой политики рекомендую смотреть ее текстовое описание через k describe networkpolicy allow-app-label
Не используйте СhatGPT. Вы не только не получите полезной информации, а даже наоборот - получите вредную. В который раз убедился, что это абсолютно бесполезная технология, по крайней мере в том виде в котором ее предоставляют на данный момент, имхо.
ок chatgpt
Alex
привет, как я могу логировать response body and request body используя аудит в k8s ? Можешь показать правило для каждого из случаев
ChatGPT
Привет! Для логирования тела запроса (request body) и тела ответа (response body) с использованием аудита в Kubernetes, вам нужно настроить соответствующие аудит-правила. Важно отметить, что логирование тела запроса может представлять потенциальные проблемы с безопасностью, поэтому следует быть осторожным при использовании такого функционала в боевой среде.
Для настройки аудита в Kubernetes, вам нужно отредактировать конфигурацию API-сервера. Вот примеры аудит-правил для логирования тела запроса и ответа:
Логирование тела запроса (request body):
apiVersion: audit.k8s.io/v1
kind: Policy
rules:
- level: Request
requestReceivedEvents:
- resources:
- group: ""
version: "v1"
resources: ["pods"]
verbs: ["create", "update", "patch"]
omitStages:
- ResponseStarted
auditPolicy:
log: true
Логирование тела ответа (response body):
apiVersion: audit.k8s.io/v1
kind: Policy
rules:
- level: RequestResponse
requestReceivedEvents:
- resources:
- group: ""
version: "v1"
resources: ["pods"]
verbs: ["create", "update", "patch"]
omitStages:
- RequestReceived
requestBody: true
responseBody: true
Обратите внимание, что эти правила предполагают, что вы хотите логировать тела запросов и ответов для операций создания (create), обновления (update) и частичного обновления (patch) ресурсов типа "pods". Вы можете настроить их под свои конкретные потребности, указав различные ресурсы, группы и вербы.
После внесения изменений в конфигурацию API-сервера, перезапустите его, чтобы изменения вступили в силу. Обратите внимание, что логирование тела запроса и ответа может создать большой объем данных, поэтому рекомендуется использовать его осторожно и только для отладочных или безопасных целей.
Alex
а что это за поля requestBody и responseBody ? Я не вижу таких в документации
ChatGPT
Извините за путаницу. Да, вы правы, в документации Kubernetes прямо указанного поля "requestBody" и "responseBody" нет. Моя ошибка.
Для логирования тела запроса и ответа, вам необходимо использовать поле auditPolicy
с параметром log
. Однако, стоит отметить, что по умолчанию Kubernetes не включает логирование тела запроса и ответа из соображений безопасности. Вместо этого, в логах сохраняются только хэши тела запроса и ответа.
Пример аудит-правила для логирования тела запроса и ответа:
apiVersion: audit.k8s.io/v1
kind: Policy
rules:
- level: RequestResponse
requestReceivedEvents:
- resources:
- group: ""
version: "v1"
resources: ["pods"]
verbs: ["create", "update", "patch"]
omitStages:
- RequestReceived
auditPolicy:
log: true
В этом примере auditPolicy
с параметром log: true
указывает API-серверу включить логирование тела запроса и ответа. Однако, учтите, что логирование тела запроса и ответа может привести к большому объему данных и повысить риск утечек конфиденциальной информации, поэтому используйте это с осторожностью и только в безопасных окружениях.
Alex
разве мы получим response body, если будем игнорировать RequestReceived ?
ChatGPT
Извините за недоразумение в предыдущем ответе. Да, вы правы, если вы исключите стадию RequestReceived
, то вы потеряете информацию о теле запроса, так как она обрабатывается на этой стадии. Однако, для получения тела ответа, вам все равно нужно будет включить стадию ResponseComplete
.
Вот исправленное правило для логирования тела запроса и ответа:
apiVersion: audit.k8s.io/v1
kind: Policy
rules:
- level: RequestResponse
requestReceivedEvents:
- resources:
- group: ""
version: "v1"
resources: ["pods"]
verbs: ["create", "update", "patch"]
omitStages:
- RequestReceived
responseReceivedEvents:
- resources:
- group: ""
version: "v1"
resources: ["pods"]
verbs: ["create", "update", "patch"]
auditPolicy:
log: true
Теперь в этом правиле мы включили исключение стадии RequestReceived
и включили стадию ResponseReceived
, чтобы получить и тело запроса, и тело ответа в логах аудита.
Alex
что это за стадия ResponseReceived ? В документации я вижу только ResponseStarted и ResponseComplete
ChatGPT
Прошу прощения за путаницу в предыдущих ответах. Да, вы правы, в документации Kubernetes указаны стадии ResponseStarted
и ResponseComplete
, но не ResponseReceived
.
Используйте следующее аудит-правило для логирования тела запроса и ответа:
apiVersion: audit.k8s.io/v1
kind: Policy
rules:
- level: RequestResponse
requestReceivedEvents:
- resources:
- group: ""
version: "v1"
resources: ["pods"]
verbs: ["create", "update", "patch"]
responseCompleteEvents:
- resources:
- group: ""
version: "v1"
resources: ["pods"]
verbs: ["create", "update", "patch"]
auditPolicy:
log: true
В этом правиле используются стадии RequestResponse
, RequestReceived
, и ResponseComplete
. Стадия RequestReceived
включена для логирования тела запроса, а стадия ResponseComplete
- для логирования тела ответа. Пожалуйста, используйте это правило в соответствии с вашими требованиями.
Alex
приведи отдельные правило для каждого из случаев
ChatGPT
Извините за путаницу. Вот два отдельных правила для логирования тела запроса и тела ответа:
Логирование тела запроса (request body):
apiVersion: audit.k8s.io/v1
kind: Policy
rules:
- level: Request
requestReceivedEvents:
- resources:
- group: ""
version: "v1"
resources: ["pods"]
verbs: ["create", "update", "patch"]
omitStages:
- ResponseComplete
auditPolicy:
log: true
Логирование тела ответа (response body):
apiVersion: audit.k8s.io/v1
kind: Policy
rules:
- level: Response
responseReceivedEvents:
- resources:
- group: ""
version: "v1"
resources: ["pods"]
verbs: ["create", "update", "patch"]
omitStages:
- RequestReceived
auditPolicy:
log: true
В первом правиле установлен уровень Request
, который логирует тело запроса. Второе правило устанавливает уровень Response
, который логирует тело ответа. Оба правила применяются к операциям создания, обновления и частичного обновления ресурсов типа "pods".
Alex
для request body разве нам надо исключить ResponseComplete, а не ResponseStarted ?
ChatGPT
Извините за недоразумение в предыдущих ответах. Да, вы правы. Для логирования тела запроса (request body
) и исключения тела ответа (response body
), вам нужно исключить стадию ResponseComplete
. Вот корректное правило для логирования тела запроса:
apiVersion: audit.k8s.io/v1
kind: Policy
rules:
- level: Request
requestReceivedEvents:
- resources:
- group: ""
version: "v1"
resources: ["pods"]
verbs: ["create", "update", "patch"]
omitStages:
- ResponseComplete
auditPolicy:
log: true
Благодарю за замечание, и я надеюсь, что это правило соответствует вашим требованиям.