{"id":813,"date":"2025-08-29T13:42:36","date_gmt":"2025-08-29T11:42:36","guid":{"rendered":"https:\/\/blog.chloesoe.ch\/?p=813"},"modified":"2025-08-29T13:50:12","modified_gmt":"2025-08-29T11:50:12","slug":"cks-notes","status":"publish","type":"post","link":"https:\/\/blog.chloesoe.ch\/?p=813","title":{"rendered":"CKS Notes"},"content":{"rendered":"<h1>General Cheatsheet<\/h1>\n<p>official cheat sheet <a href=\"https:\/\/kubernetes.io\/docs\/reference\/kubectl\/cheatsheet\/\">https:\/\/kubernetes.io\/docs\/reference\/kubectl\/cheatsheet\/<\/a>, here some favourites of mine, not only CKS specific.<\/p>\n<pre><code># `tail -f` pod\nkubectl logs my-pod --tail=10 -f\n\n# create yaml from image\nkubectl -n mynamespace run mynginx --dry-run=client --image=nginx:1.14 -o yaml  &gt; mynginx.yml\n\n# permanently save the namespace for all subsequent kubectl commands in that context.\nkubectl config set-context --current --namespace=ggckad-s2\n\n# get all objects in a namespace\nk get all -n $namespace\nkubectl get all -A    # in all namespaces\nkubectl get sa   # ServiceAccounts not included\n\n# show RBAC\nkubectl describe role $ROLE\n\n# use --show-labels to help with network plolicies\nkubectl -n mordor get pods mtdoom --show-labels\nkubectl get namespaces --show-label<\/code><\/pre>\n<h1>0. Course Meta Information<\/h1>\n<h2>0.1. Exam Info<\/h2>\n<h3>0.1.1. Exam Remote Desktop<\/h3>\n<p>Worth to read <a href=\"https:\/\/itnext.io\/cks-cka-ckad-changed-terminal-to-remote-desktop-157a26c1d5e\">https:\/\/itnext.io\/cks-cka-ckad-changed-terminal-to-remote-desktop-157a26c1d5e<\/a> about Copy Past etc.<\/p>\n<h3>0.1.2. Allowed Documentation for the Exam<\/h3>\n<ul>\n<li><a href=\"https:\/\/kubernetes.io\/docs\/\">https:\/\/kubernetes.io\/docs\/<\/a><\/li>\n<li><a href=\"https:\/\/github.com\/kubernetes\">https:\/\/github.com\/kubernetes<\/a><\/li>\n<li><a href=\"https:\/\/kubernetes.io\/blog\">https:\/\/kubernetes.io\/blog<\/a><\/li>\n<li><a href=\"https:\/\/github.com\/aquasecurity\/trivy\">https:\/\/github.com\/aquasecurity\/trivy<\/a><\/li>\n<li><a href=\"https:\/\/docs.sysdig.com\">https:\/\/docs.sysdig.com<\/a><\/li>\n<li><a href=\"https:\/\/falco.org\/docs\">https:\/\/falco.org\/docs<\/a><\/li>\n<li><a href=\"https:\/\/gitlab.com\/apparmor\/apparmor\/-\/wikis\/Documentation\">https:\/\/gitlab.com\/apparmor\/apparmor\/-\/wikis\/Documentation<\/a><\/li>\n<\/ul>\n<h3>0.1.3. Portal<\/h3>\n<p><a href=\"https:\/\/trainingportal.linuxfoundation.org\/learn\/dashboard\/\">https:\/\/trainingportal.linuxfoundation.org\/learn\/dashboard\/<\/a><\/p>\n<p>\u2192 <a href=\"https:\/\/trainingportal.linuxfoundation.org\/learn\/course\/certified-kubernetes-security-specialist-cks\/\">https:\/\/trainingportal.linuxfoundation.org\/learn\/course\/certified-kubernetes-security-specialist-cks\/<\/a><\/p>\n<h2>0.2. Prepare Environment in Course Labs and Exam<\/h2>\n<h3>0.2.1. Kube env<\/h3>\n<p><a href=\"https:\/\/kubernetes.io\/docs\/reference\/kubectl\/cheatsheet\/#bash\">https:\/\/kubernetes.io\/docs\/reference\/kubectl\/cheatsheet\/#bash<\/a><\/p>\n<pre><code>source &lt;(kubectl completion bash) # setup autocomplete in bash into the current shell, bash-completion package should be installed first.\necho &quot;source &lt;(kubectl completion bash)&quot; &gt;&gt; ~\/.bashrc # add autocomplete permanently to your bash shell.\n\nalias k=kubectl\ncomplete -o default -F __start_kubectl k\n\ncat &gt;&gt; ~\/.bash_aliases &lt;&lt;-EOF\nalias k=kubectl\ncomplete -o default -F __start_kubectl k\nEOF\n\n# some tweak for `less`\nexport LESS=&quot;IFRX&quot;\necho &#039;export LESS=&quot;IFRX&quot;&#039; &gt;&gt; ~\/.bashrc<\/code><\/pre>\n<h3>0.2.2. Vimrc<\/h3>\n<pre><code>cat &gt;&gt; ~\/.vimrc &lt;&lt;-EOF\nset laststatus=2\nset hlsearch\nset number\nset tabstop=2 shiftwidth=2 expandtab\nset autoindent\nEOF<\/code><\/pre>\n<h2>0.3. Acloud.Guru Course Tips and Tricks<\/h2>\n<p>Regarding acloud.guru CKS course <a href=\"https:\/\/learn.acloud.guru\/course\/certified-kubernetes-security-specialist\/dashboard\">https:\/\/learn.acloud.guru\/course\/certified-kubernetes-security-specialist\/dashboard<\/a><\/p>\n<p>Some facts:<\/p>\n<ul>\n<li>it could be worth,  to have an own cluster running to directly test interesting stuff there.<\/li>\n<li>To listen to all chapters and to the chapter labs, I invested 26h. This is without the 12 thirty minute labs at the end.\n<ul>\n<li>So you could take 3 education leave days to go throu the whole course<\/li>\n<li>Sometimes you can spend a bit more time, if you're interested in a topic<\/li>\n<\/ul>\n<\/li>\n<li>For the labs and the killer.sh preparation you can take the other 2d of education leave<br \/>\n<h1>1. 01 - Install Kubeadm<\/h1>\n<\/li>\n<\/ul>\n<p><a href=\"https:\/\/kubernetes.io\/docs\/setup\/production-environment\/tools\/kubeadm\/install-kubeadm\/\">https:\/\/kubernetes.io\/docs\/setup\/production-environment\/tools\/kubeadm\/install-kubeadm\/<\/a><\/p>\n<p><a href=\"https:\/\/kubernetes.io\/docs\/setup\/production-environment\/tools\/kubeadm\/create-cluster-kubeadm\/\">https:\/\/kubernetes.io\/docs\/setup\/production-environment\/tools\/kubeadm\/create-cluster-kubeadm\/<\/a><\/p>\n<h2>1.1. IPv6<\/h2>\n<p>On my  test cluster, the worker node cannot connect to the master, test was to disable ipv6, according to <a href=\"https:\/\/github.com\/kubernetes-sigs\/kubespray\/issues\/6014\">https:\/\/github.com\/kubernetes-sigs\/kubespray\/issues\/6014<\/a>, but not working yet<\/p>\n<pre><code># if IPV6 tagged to your network interface ,do this commands to disable.\n\nifconfig -a | grep inet6\n\n# add lines in \/etc\/sysctl.d\/99-kubernetes-cri.conf\nnet.ipv6.conf.all.disable_ipv6 = 1\nnet.ipv6.conf.default.disable_ipv6 = 1\n\nsudo sysctl --system\n<\/code><\/pre>\n<h1>2. 02 - Cluster Setup Review<\/h1>\n<h2>2.1. Exam Tips Section 2<\/h2>\n<p>Source: acloud.guru course <\/p>\n<ul>\n<li>NetworkPolicy\n<ul>\n<li>Tip 1: Default deny + Targeted policies to block all but necessary traffic in a namespace<\/li>\n<li>Tip 2: Use an empty podSelector: {} to apply the to all Pods in the namespace<\/li>\n<li>Tip 3: Pay attention to the difference between one rule with multiple selectors and multiple rules (e.g. a dash &quot;-&quot;  can make a difference)<\/li>\n<\/ul>\n<\/li>\n<li>CIS Benchmark\n<ul>\n<li>Tip 1: CIS Kubernetes Benchmark - A set of standards and best practices for a secure Kubernetes cluster<\/li>\n<li>Tip 2: kube-bench - Runs automated tests to checvk how well your cluster conforms to the CIS Benchmark<\/li>\n<li>Tip 3: kubeadm clusters use a kubelet config file located at \/var\/lib\/kubelet\/config.yaml  on each node<\/li>\n<li>Tip 4: In a kubeadm cluster, manifest files for control plane components (API server, etcd, etc.) can be found in \/etc\/kubernetes\/manifests  on the control plane server<\/li>\n<\/ul>\n<\/li>\n<li>Ingress:\n<ul>\n<li>Tip 1: You can implement TLS termination using an Ingress<\/li>\n<li>Tip 2: Store TLS certificates using a Secret. Pass the Secret to the Ingress using spec.tls[].secretName <\/li>\n<li>Tip 3: Bookmark the Ingres -TLS documentation (<a href=\"https:\/\/kubernetes.io\/docs\/concepts\/services-networking\/ingress\/#tls\">https:\/\/kubernetes.io\/docs\/concepts\/services-networking\/ingress\/#tls<\/a>)<\/li>\n<\/ul>\n<\/li>\n<li>More Tips:\n<ul>\n<li>Tip 1: Kubernetes servers use certain ports to provide Kubernetes functionality. So be aware that you may need to protect those ports in the real world.<\/li>\n<li>Tip 2:  if you use any graphical interfaces for Kubernetes, be aware that they also present a target for attack, and make sure to keep them secure.<\/li>\n<li>Tip 3:  When installing Kubernetes binaries manually, you can use those checksums to validate your Kubernetes binaries to make sure that they haven't been altered.<br \/>\n<h2>2.2. Network policies<\/h2>\n<\/li>\n<\/ul>\n<\/li>\n<\/ul>\n<p>Additional dash here would mean a separate item in the array. This ingress would be allowed for pods in namespace &quot;test&quot; OR apps with label &quot;client&quot;. If you want to have it combined, you need to write it without dash so it only allows if both conditions are met<\/p>\n<h3>2.2.1.1.1. deny all network policy<\/h3>\n<pre><code>apiVersion: networking.k8s.io\/v1\nkind: NetworkPolicy\nmetadata:\n  name: test-network-policy\n  namespace: default\nspec:\n  podSelector: {}\n  policyTypes:\n    - Ingress\n    - Egres<\/code><\/pre>\n<h2>2.3. CSI Benchmark<\/h2>\n<p>kube-bench <\/p>\n<pre><code>$ wget -O kube-bench-control-plane.yaml https:\/\/raw.githubusercontent.com\/aquasecurity\/kube-bench\/main\/job-master.yaml\n$ wget -O kube-bench-node.yaml https:\/\/raw.githubusercontent.com\/aquasecurity\/kube-bench\/main\/job-node.yaml\n\n$ kubectl create -f kube-bench-control-plane.yaml\njob.batch\/kube-bench-master created\n$ kubectl create -f kube-bench-node.yaml\njob.batch\/kube-bench-node created\n$ kubectl get jobs.batch\nNAME                COMPLETIONS   DURATION   AGE\nkube-bench-master   1\/1           12s        15s\nkube-bench-node     0\/1           7s         7s\n\n$ kubectl logs kube-bench-master-r8qkx &gt; kube-bench-results-control-plane.log\n$ kubectl logs kube-bench-node-mvkb8 &gt; kube-bench-results-node.log<\/code><\/pre>\n<h2>2.4. Implementing TLS with Ingress<\/h2>\n<p>Secret and Ingress needed, important bookmark: <a href=\"https:\/\/kubernetes.io\/docs\/concepts\/services-networking\/ingress\/#tls\">https:\/\/kubernetes.io\/docs\/concepts\/services-networking\/ingress\/#tls<\/a><\/p>\n<p>self signed cert:<\/p>\n<pre><code>openssl req -nodes -new -x509 -keyout  accounts.key -out accounts.crt -subj &quot;\/CN=accounts.svc&quot;<\/code><\/pre>\n<p>base64 could bi imported in the yaml in vim with:<\/p>\n<pre><code>:read !base64 accounts.key<\/code><\/pre>\n<p>Multi line YAML string:<\/p>\n<pre><code>apiVersion: v1\nkind: Secret\nmetadata:\n  name: accounts-secret\n  namespace: accounts\ndata:\n  tls.crt: |\n    LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUREekNDQWZlZ0F3SUJBZ0lVUFN4Yk9qdGFF\n    M3BpQnUveW5XQVNpSG9rcTBvd0RRWUpLb1pJaHZjTkFRRUwKQlFBd0Z6RVZNQk1HQTFVRUF3d01Z\n    V05qYjNWdWRITXVjM1pqTUI0WERUSXlNVEV5TVRFM01qRXhORm9YRFRJeQpNVEl5TVRFM01qRXhO\n    ...\n    VFBuUlV6SUpZUlE9PQotLS0tLUVORCBDRVJUSUZJQ0FURS0tLS0tCg==\n  tls.key: |\n    LS0tLS1CRUdJTiBQUklWQVRFIEtFWS0tLS0tCk1JSUV2d0lCQURBTkJna3Foa2lHOXcwQkFRRUZB\n    ...\ntype: kubernetes.io\/tls<\/code><\/pre>\n<h2>2.5. Verify your kubectl version sha256 checksum<\/h2>\n<p>source <a href=\"https:\/\/kubernetes.io\/docs\/tasks\/tools\/install-kubectl-linux\/#install-kubectl-binary-with-curl-on-linux\">https:\/\/kubernetes.io\/docs\/tasks\/tools\/install-kubectl-linux\/#install-kubectl-binary-with-curl-on-linux<\/a>, some basteling to have it one-line done by me<\/p>\n<pre><code># get version of kubectl\nkubectl version --short --client\n\n# get checksum of current version\ncurl -LO &quot;https:\/\/dl.k8s.io\/`kubectl version --short --client | cut -f3 -d&#039; &#039;`\/bin\/linux\/amd64\/kubectl.sha256&quot;\n\n# check the checksum of your kubecetl binary\necho &quot;$(&lt;kubectl.sha256)  `whereis kubectl | cut -f2 -d&#039; &#039;`&quot; | sha256sum --check\n\n# direct check for kubectl\necho $(curl -Ls &quot;https:\/\/dl.k8s.io\/`kubectl version --short --client | cut -f3 -d&#039; &#039;`\/bin\/linux\/amd64\/kubectl.sha256&quot;) $(whereis kubectl | cut -f2 -d&#039; &#039;) | sha256sum --check\necho $(curl -sL &quot;https:\/\/dl.k8s.io\/`kubectl version --short --client 2&gt;\/dev\/null | grep &quot;Client Version&quot; | cut -f2 -d: | tr -d &quot;[:blank:]&quot;`\/bin\/linux\/amd64\/kubectl.sha256&quot; | tee) \/usr\/bin\/kubectl  | sha256sum --check\n\n# you can do the same for kubelet\necho $(curl -Ls &quot;https:\/\/dl.k8s.io\/`kubelet --version | cut -f2 -d&#039; &#039;`\/bin\/linux\/amd64\/kubelet.sha256&quot;) $(whereis kubelet | cut -f2 -d&#039; &#039;) | sha256sum --check<\/code><\/pre>\n<h1>3. Cluster Hardening<\/h1>\n<h2>3.1. Exam Tips Section 3<\/h2>\n<p>Source: acloud.guru course <\/p>\n<pre><code>Service Accounts\n\n    Tip 1: If a container is compromised, an attacker could use the ServiceAccount to access the Kubernetes API\n\n    Tip 2: Use Kubernetes RBAC to control what ServiceAccounts can do and limit permissions\n\nService Account Permissions \/ Role Based Access Control (RBAC)\n\n    Tip 1: Examine existing RoleBindings and ClusterRoleBindings to determine what permissions a service account has\n\n    Tip 2: Design your RBAC setup in such a way that service accounts don't have unnecessary permissions\n\n    Tip 3: You can bind multiple roles to an account. Use this to keep Roles separate rather that overloading them with a lot of permissions\n\n    Tip 4: You can bind a ClusterRole with a RoleBinding to to proviede the necessary permissions only within the RoleBindings's namespace\n\nRestricting Access to the Kubernetes API\n\n    Tip 1: Use RBAC to control user permissions within the API. Make sure accounts do not have permissions they do not need\n\n    Tip 2: Limit network access to the API to prevent attackers from being able to communicate\n\nKeep k8s up to date\n\n    Tip 1: Keep k8s up to date to take advantage of the latest security patches\n\n    Tip 2: Since version 1.19 major releases receive approximately one year of patch support.<\/code><\/pre>\n<h2>3.2. Service Accounts<\/h2>\n<p><a href=\"https:\/\/kubernetes.io\/docs\/tasks\/configure-pod-container\/configure-service-account\/\">https:\/\/kubernetes.io\/docs\/tasks\/configure-pod-container\/configure-service-account\/<\/a><\/p>\n<p><a href=\"https:\/\/kubernetes.io\/docs\/reference\/access-authn-authz\/rbac\/\">https:\/\/kubernetes.io\/docs\/reference\/access-authn-authz\/rbac\/<\/a><\/p>\n<pre><code>---\n\napiVersion: v1\nkind: ServiceAccount\nmetadata:\n  name: build-robot\n  namespace: default\n\n---\napiVersion: rbac.authorization.k8s.io\/v1\nkind: Role\nmetadata:\n  namespace: default\n  name: pod-reader\nrules:\n- apiGroups: [&quot;&quot;] # &quot;&quot; indicates the core API group\n  resources: [&quot;pods&quot;]\n  verbs: [&quot;get&quot;, &quot;watch&quot;, &quot;list&quot;]\n\n---\n\napiVersion: rbac.authorization.k8s.io\/v1\n# This role binding allows &quot;jane&quot; to read pods in the &quot;default&quot; namespace.\n# You need to already have a Role named &quot;pod-reader&quot; in that namespace.\nkind: RoleBinding\nmetadata:\n  name: read-pods\n  namespace: default\nsubjects:\n# You can specify more than one &quot;subject&quot;\n- kind: User\n  name: jane # &quot;name&quot; is case sensitive\n  apiGroup: rbac.authorization.k8s.io\nroleRef:\n  # &quot;roleRef&quot; specifies the binding to a Role \/ ClusterRole\n  kind: Role #this must be Role or ClusterRole\n  name: pod-reader # this must match the name of the Role or ClusterRole you wish to bind to\n  apiGroup: rbac.authorization.k8s.io<\/code><\/pre>\n<pre><code>kubectl describe roles\nName:         auth-sa-role\nLabels:       &lt;none&gt;\nAnnotations:  &lt;none&gt;\nPolicyRule:\n  Resources  Non-Resource URLs  Resource Names  Verbs\n  ---------  -----------------  --------------  -----\n  endpoints  []                 []              [get list]\n  pods\/log   []                 []              [get list]\n  pods       []                 []              [get list]\n  services   []                 []              [get list]<\/code><\/pre>\n<h1>4. System Hardening<\/h1>\n<h2>4.1. Exam Tips Section 4<\/h2>\n<p>Source: acloud.guru course <\/p>\n<ul>\n<li>Host OS Secuirty\n<ul>\n<li>Tip 1: Protect your hosts from attacks that might come from within containers.<\/li>\n<li>Tip 2: Beware of Pod settingse like hostIPC, hostNetwork, hostPID. Use them only when absolutely necessary.<\/li>\n<\/ul>\n<\/li>\n<li>IAM Roles\n<ul>\n<li>Tip 1:  If you are running K8s in AWS, your container applications may be able to access IAM credentials<\/li>\n<li>Tip 2: Avoid providing unnecessary permissions to IAM roles (principle of least privilege)<\/li>\n<li>Tip 3: If your app does not need IAM access, consider blockeing access to IAM credentials via firewall, NetworkPolicy, etc.<\/li>\n<\/ul>\n<\/li>\n<li>Network Level Secuirty\n<ul>\n<li>Tip 1: By default, anyone who can access the cluster network can communicate with all Pods and Services in the cluster<\/li>\n<li>aka, log-in via SSH you have full access<\/li>\n<li>Tip 2: When possible, limit access to the cluster network from outside<\/li>\n<\/ul>\n<\/li>\n<li>AppArmor\n<ul>\n<li>Tip 1: AppArmor is a Linux kerne security module that allows granular control over what individual programs can and cannot do<\/li>\n<li>Tip 2: Load a profile in enforce mode (aka &quot;enforcing the profile&quot;) to actively prevent programs from doing anything the profile does not allow.<\/li>\n<li>Tip 3: Load a profile in complain mode to simly report on what the program is doing<\/li>\n<\/ul>\n<\/li>\n<li>AppArmor in Containers\n<ul>\n<li>Tip 1: Use apparmor_parser  command to load an AppArmonr profile from a file. It will load the profile in enforcing mode by default.<\/li>\n<li>Tip 2: Use Pod annotations to apply an AppArmor profile to a container: For example:\n<pre><code>container.apparmor.security.beta.kkubernetes.io\/nginx: localhost\/k8s-deny-write<\/code><\/pre>\n<\/li>\n<\/ul>\n<\/li>\n<\/ul>\n<h2>4.2. Host OS Security<\/h2>\n<p>It is possible to run the container in the Host Namespace<\/p>\n<p>To be enabled with hostIPC, hostNetwork, hostPID<\/p>\n<p>Priviledged Mode: containers[].securityContext.priviledged \u2192 true. With that Pod has access to Host Ressources.<\/p>\n<h2>4.3. IAM Roles<\/h2>\n<p>Only relevant for Amazon AWS<\/p>\n<h2>4.4. AppArmor<\/h2>\n<h3>4.4.1.1.1. to check if AppArmor is enabled on your nodes<\/h3>\n<pre><code>kubectl get nodes -o=jsonpath=&#039;{range .items[*]}{@.metadata.name}: {.status.conditions[?(@.reason==&quot;KubeletReady&quot;)].message}{&quot;\\n&quot;}{end}&#039;<\/code><\/pre>\n<p>two modes<\/p>\n<ul>\n<li>enforce mode<\/li>\n<li>complain mode<\/li>\n<\/ul>\n<pre><code>sudo apparmor_parser \/path\/to\/file <\/code><\/pre>\n<p>-C  complain mode<\/p>\n<p><a href=\"https:\/\/kubernetes.io\/docs\/tutorials\/security\/apparmor\/#example\">https:\/\/kubernetes.io\/docs\/tutorials\/security\/apparmor\/#example<\/a><\/p>\n<p>example<\/p>\n<pre><code>apiVersion: v1\nkind: Pod\n metadata:\n  name: password-db\n  namespace: auth\n  annotations:\n    # Tell Kubernetes to apply the AppArmor profile.\n    container.apparmor.security.beta.kubernetes.io\/password-db: localhost\/k8s-deny-write\nspec:\n  containers:\n  - name: password-db\n    image: radial\/busyboxplus:curl\n    command: [&#039;sh&#039;, &#039;-c&#039;, &#039;while true; do if echo &quot;The password is hunter2&quot; &gt; password.txt; then echo &quot;Password hunter2 logged.&quot;; else echo &quot;Password log attempt blocked.&quot;; fi; sleep 5; done&#039;]<\/code><\/pre>\n<h1>5. Minimizing Microservice Vulnerabilities<\/h1>\n<h2>5.1. Exam Tips Section 5<\/h2>\n<p>Source: acloud.guru course <\/p>\n<ul>\n<li>Managing Container Access with Security Contexts\n<ul>\n<li>Tip 1: securityContext offers a variety of security and access control-related settings<\/li>\n<li>Tip 2: spec.securityContext sets securityContext settings at the Pod level. These settings apply to all containers in the Pod<\/li>\n<li>Tip 3: spec.containers[].securityContext sets securityContext settings at the container level. These settings apply to individual containers within the pod<\/li>\n<\/ul>\n<\/li>\n<li>PodSecurityPolicies\n<ul>\n<li>Tip 1: Use Pod security policies to enforce desired security configurations for new Pods<\/li>\n<li>Tip 2: Pod security policies can reject Pods that don't meet the desired standard, or modify Pods by applying default settings.<\/li>\n<\/ul>\n<\/li>\n<li>Using Pod Security Policies\n<ul>\n<li>Tip 1: To use them you must first enable PodSecurityPolicy  admission controller. Use the --enable-admission-plugins flag on the kube-apiserver to do this<\/li>\n<li>Use documentation for v1.24.x, does not exist on v1.25.x documentation <a href=\"https:\/\/v1-24.docs.kubernetes.io\/docs\/concepts\/security\/pod-security-policy\/\">https:\/\/v1-24.docs.kubernetes.io\/docs\/concepts\/security\/pod-security-policy\/<\/a><\/li>\n<li>Where to enable isn't good documented, you have to add PodSecurityPolicy  to --enable-admission-plugins in \/etc\/kubernetes\/manifests\/kube-apiserver.yaml <\/li>\n<li>Tip 2: In order to create a Pod, a user (or the Pod's ServiceAccount) must be authorized to use a PodSecurityPolicy via the use verb in RBAC<\/li>\n<li>Tip 3: To apply a PodSecurityPolicy within the context of a specific namepace, authorize a ServiceAccount in that namespace to use the policy.<\/li>\n<\/ul>\n<\/li>\n<li>OPA Gatekeeper\n<ul>\n<li>Tip 1: Open Policy Agent (OPA) Gatekeeper allows you to enforce custom policies on any k8s object at creation time<\/li>\n<li>Tip 2: Constraint Templates define reusable constraint logic and any parameters that can be passed in<\/li>\n<li>Tip 3: Constraint objects apply a Constraint Template to a specific group of potential incoming objects, alongside specific parameters.<\/li>\n<\/ul>\n<\/li>\n<li>Secrets\n<ul>\n<li>Tip 1: Secrets store sensitive data, and can pass it to containers<\/li>\n<li>Tip 2: You can pass secret data to a container using either environment variables or mounted volumes<\/li>\n<li>Tip 3: To retrieve secret data from the command line, you can use kubectl get -o yaml  to get the base64-encoded data, then decode it with bas64 --decode<\/li>\n<\/ul>\n<\/li>\n<li>Understanding Container Runtime Sandboxes\n<ul>\n<li>Tip 1: Container Runtime Sandboxes provide a specialized runtime with additional layers of isolation, allowing you to run untrusted workloads more securely<\/li>\n<li>Tip 2: gVisor creates a runtime sandbox by running a Linux application kernel within the host OS. runssc is the OCI-compliant container runtime that allows Kubernetes to interface with gVisor<\/li>\n<li>Tip 3. Kata Containers create a sandbox by transparently running containers inside of lightweight VMs.<\/li>\n<\/ul>\n<\/li>\n<li>Creating a Container Runtime Sandbox\n<ul>\n<li>Tip 1: Use a RuntimeClass to define a specialized container runtime configuration, such as one that will use gVisor\/runsc<\/li>\n<li>Tip 2: Set the runtimeClassName property in a Pod specification to make the Pod use the container runtime sandbox<\/li>\n<\/ul>\n<\/li>\n<li>Understanding Pod-to-Pod mTLS\n<ul>\n<li>Tip 1: mTLS means clients and servers mutually authenticate wit heach other and encrypt their communications<\/li>\n<li>Tip 2: You can obtain certificates using the K8s API<\/li>\n<\/ul>\n<\/li>\n<li>Signing Certificates\n<ul>\n<li>Tip 1: Create a CertificateSigningRequest object to request a new ceritificate<\/li>\n<li>Tip 2: Manage, approve, or deny requests via the command line with kubectl certificate<\/li>\n<li>Tip 3: Once approved, the signed certificate can be retrieved from the status.certificate  field of the CertificateSigningRequest<\/li>\n<\/ul>\n<\/li>\n<\/ul>\n<h2>5.2. securityContexts<\/h2>\n<p>Can be set in Pod spec and Container spec. Options differ for securityContext if you run it in Pod or Container context.<\/p>\n<h2>5.3. PodSecurityPolicies<\/h2>\n<p>Will be deprecated, documentation for v1.25.x not available any more, go to <a href=\"https:\/\/v1-24.docs.kubernetes.io\/\">https:\/\/v1-24.docs.kubernetes.io\/<\/a>, see <a href=\"https:\/\/v1-24.docs.kubernetes.io\/docs\/concepts\/security\/pod-security-policy\/\">https:\/\/v1-24.docs.kubernetes.io\/docs\/concepts\/security\/pod-security-policy\/<\/a><\/p>\n<p>for old documentation<\/p>\n<p>not turned on by default, admission controller must be enabled with <\/p>\n<h2>5.4. Using Pod Security Policies<\/h2>\n<p>Once turned on, you have to activate at least one policy, otherwise all pods are rejected.<\/p>\n<p>RBAC needed to authorize via ServiceAccount (preferred over User)<\/p>\n<h3>5.4.1. Enable the Use of PodSecurityPolicies in the Cluster<\/h3>\n<ol>\n<li>Edit the manifest file for the Kube API server:\n<pre><code>sudo vi \/etc\/kubernetes\/manifests\/kube-apiserver.yaml<\/code><\/pre>\n<\/li>\n<li>Under the command section in the YAML file, modify the --enable-admission-plugins flag to read:\n<pre><code>- --enable-admission-plugins=NodeRestriction,PodSecurityPolicy<\/code><\/pre>\n<\/li>\n<li>Save and exit the file by pressing the Escape key and entering:\n<pre><code>:wq<\/code><\/pre>\n<\/li>\n<li>Ensure the files are working correctly. This may take a few tries before results appear:\n<pre><code>kubectl get nodes <\/code><\/pre>\n<\/li>\n<\/ol>\n<h2>5.5. OPA Gatekeeper<\/h2>\n<p>rules to create an object.<\/p>\n<p>Rego language used for actual rule programming in yaml.<\/p>\n<p>A Constraint Template needed and we can create one or more constraints out of it. A constraint is an implementation of a constraint template.<\/p>\n<p>The Constraint Template implements a new kind  which we use to create new Constraint objects<\/p>\n<h2>5.6. Secrets<\/h2>\n<pre><code>cloud_user@k8s-control:~$ kubectl get secrets -n users\nNAME      TYPE     DATA   AGE\ndb-pass   Opaque   1      94m\ncloud_user@k8s-control:~$ kubectl get secrets -n users db-pass -o yaml\napiVersion: v1\ndata:\n  password: aHVudGVyMgo=\nkind: Secret\nmetadata:\n\n...\n\ncloud_user@k8s-control:~$ echo aHVudGVyMgo= | base64 --decode\nhunter2<\/code><\/pre>\n<h2>5.7. Runtime Sandboxes<\/h2>\n<p>Could be interesting for multi tenancy, but is costly regarding performance.<\/p>\n<h2>5.7.1. implementations<\/h2>\n<p>gVisor\/runsc: Kernel inside Kernel, something between Container and VM.<\/p>\n<p>Kata Containers: lightweight VMs<\/p>\n<p><a href=\"https:\/\/kubernetes.io\/docs\/concepts\/containers\/runtime-class\/\">https:\/\/kubernetes.io\/docs\/concepts\/containers\/runtime-class\/<\/a> \u2192 <a href=\"https:\/\/kubernetes.io\/docs\/concepts\/containers\/runtime-class\/#usage\">https:\/\/kubernetes.io\/docs\/concepts\/containers\/runtime-class\/#usage<\/a><\/p>\n<h3>5.7.1.1.1. Install gVisor<\/h3>\n<pre><code>curl -fsSL https:\/\/gvisor.dev\/archive.key | sudo apt-key add -\nsudo add-apt-repository &quot;deb [arch=amd64,arm64] https:\/\/storage.googleapis.com\/gvisor\/releases release main&quot;\nsudo apt-get update &amp;&amp; sudo apt-get install -y runsc<\/code><\/pre>\n<pre><code># RuntimeClass is defined in the node.k8s.io API group\napiVersion: node.k8s.io\/v1\nkind: RuntimeClass\nmetadata:\n  # The name the RuntimeClass will be referenced by.\n  # RuntimeClass is a non-namespaced resource.\n  name: myruntime\n# The name of the corresponding CRI configuration\n# this is the name we configured in \/etc\/containerd\/config.toml\nhandler: runsc<\/code><\/pre>\n<p>usage <\/p>\n<pre><code>apiVersion: v1\nkind: Pod\nmetadata:\n  name: mypod\nspec:\n  runtimeClassName: runsc-sandbox\n\nkubectl exec non-sandbox-pod -- dmesg\n\n# first line shows kernel of current os, because it is running un-sandboxed.\n\n kubectl exec sandbox-pod -- dmesg<\/code><\/pre>\n<h2>5.8. mTLS and Certificates<\/h2>\n<p>Mutual Transport Layer Security; both communication parties fully authenticate each other.<\/p>\n<p>Certificate Signing<\/p>\n<p>sidenode interesting tool cfssl to create certificates: <a href=\"https:\/\/github.com\/cloudflare\/cfssl\">https:\/\/github.com\/cloudflare\/cfssl<\/a><\/p>\n<h3>5.8.1. Create a CertificateSigningRequest<\/h3>\n<pre><code>sudo apt-get install -y golang-cfssl<\/code><\/pre>\n<h3>5.8.1.1.1. Generate a CSR file.<\/h3>\n<pre><code># according to https:\/\/kubernetes.io\/docs\/tasks\/tls\/managing-tls-in-a-cluster\/#create-a-certificate-signing-request\ncat &lt;&lt;EOF | cfssl genkey - | cfssljson -bare k8cert.chloesoe.ch\n{\n    &quot;hosts&quot;: [\n        &quot;saanen.chloesoe.ch&quot;,\n        &quot;lauenen.chloesoe.ch&quot;,\n        &quot;213.167.224.157&quot;,\n        &quot;185.142.215.9&quot;\n    ],\n    &quot;CN&quot;: &quot;system:node:tls-pod.tls-test.pod.cluster.local&quot;,\n    &quot;key&quot;: {\n        &quot;algo&quot;: &quot;ecdsa&quot;,\n        &quot;size&quot;: 256\n    },\n    &quot;names&quot;: [\n    {\n        &quot;O&quot;: &quot;system:nodes&quot;\n    }\n    ]\n}\nEOF\n\n# copy the base64 of the csr for later usag\ncat k8cert.chloesoe.ch.csr | base64<\/code><\/pre>\n<p>Create a CertificateSigningRequest object <a href=\"https:\/\/kubernetes.io\/docs\/tasks\/tls\/managing-tls-in-a-cluster\/#create-a-certificatesigningrequest-object-to-send-to-the-kubernetes-api\">https:\/\/kubernetes.io\/docs\/tasks\/tls\/managing-tls-in-a-cluster\/#create-a-certificatesigningrequest-object-to-send-to-the-kubernetes-api<\/a><\/p>\n<pre><code># create CSR yaml, with base64 from CSR\ncat &gt;&gt; tls-svc-csr.yml &lt;&lt;EOF\napiVersion: certificates.k8s.io\/v1\nkind: CertificateSigningRequest\nmetadata:\n  name: tls-svc-csr\nspec:\n  request: $(cat k8cert.chloesoe.ch.csr | base64 | tr -d &#039;\\n&#039;)\n  signerName: example.com\/serving\n  usages:\n  - digital signature\n  - key encipherment\n  - server auth\nEOF\n\n# create object\nkubectl create -f tls-svc-csr.yml\n\n# check status\nkubectl get csr<\/code><\/pre>\n<p>Approve the CertificateSigningRequest<\/p>\n<pre><code>sudo falco -r nginx-rules.yml -M 45kubectl get csr -o wide\nNAME          AGE   SIGNERNAME                    REQUESTOR          REQUESTEDDURATION   CONDITION\ntls-svc-csr   5s    example.com\/serving           kubernetes-admin   &lt;none&gt;              Pending\n\n# approve\nkubectl certificate approve tls-svc-csr\n\n# now approved, should alse be Issued in order to have a certificate\nkubectl get csr\nNAME          AGE   SIGNERNAME                    REQUESTOR          REQUESTEDDURATION   CONDITION\ntls-svc-csr   51s   example.com\/serving           kubernetes-admin   &lt;none&gt;              Approved,Issued\n\n# Retrieve the signed certificate data.\nkubectl get csr tls-svc-csr -o yaml\nkubectl get csr tls-svc-csr -o jsonpath=&#039;{.status.certificate}&#039; | base64 --decode<\/code><\/pre>\n<h1>6. Supply Chain Security Intro<\/h1>\n<h2>6.1. Exam Tips Section 6<\/h2>\n<p>Source: acloud.guru course <\/p>\n<ul>\n<li>Images\n<ul>\n<li>Minimizing Base Image Attack Surface\n<ul>\n<li>Tip 1: Try to use images that run up-to-date software to minimize software vulnerabilities<\/li>\n<li>Tip 2: Minimize the presence of unnecessary software in images that could increase security risks<\/li>\n<li>Tip 3: Beware of the possiblity of images that have been compromised by an attacker<\/li>\n<\/ul>\n<\/li>\n<\/ul>\n<\/li>\n<li>Whitelisting Registries\n<ul>\n<li>Tip 1: Limit users to only trusted image registries to prevent them from running images from untrusted sources in the cluster<\/li>\n<li>Tip 2: You can limit registries using OPA Gatekeeper<\/li>\n<\/ul>\n<\/li>\n<li>Image Validation\n<ul>\n<li>Tip 1: Container images can be signed with a hash generated from the image contents<\/li>\n<li>Tip 2: To validate the image, you can append the hash to the image reference in your container spec with image: imageName:tag@sha256:hash <\/li>\n<\/ul>\n<\/li>\n<li>Static Analyzing\n<ul>\n<li>Dockerfiles\n<ul>\n<li>Tip 1: Avoid user root \u2192 Final USER directive must not be root or 0<\/li>\n<li>Tip 2: Avoid :latest  tag<\/li>\n<li>Tip 3: Avoid unnecessary Software<\/li>\n<li>Tip 4: Avoid not storing sensitive Data<\/li>\n<\/ul>\n<\/li>\n<li>YAML Files\n<ul>\n<li>Tip 1: When possible, avoid Host Namespaces in your Pod configuration (i.e. hostIPC, hostNetwork, hostPID)<\/li>\n<li>Tip 1: When possible, avoid Privileged mode with privileged: true<\/li>\n<li>Tip 3: Avoid running user as root or 0 in securityContext.runAsUser <\/li>\n<li>Tip 3: Don't use the  :latest  tag, but instead use a specific fixed tag to avoid downloading a new and potentially unvetted image<\/li>\n<\/ul>\n<\/li>\n<\/ul>\n<\/li>\n<li>Vulnerability Scanning\n<ul>\n<li>Tip 1: Vulnerability scanning allows you to scan images to detect security vulnerabilities that have already been discovered and documented by security researchers<\/li>\n<li>Tip 2: Trivy is a command-line tool that allows you to scan images by name and tag<\/li>\n<li>Tip 3: Scan an image name with Trivy with: trivy image quay.io\/keycloak\/keycloak:20.0.0<\/li>\n<li>Tip 4: In older versions it could be only trivy $IMAGENAME  without &quot;image&quot; keyword<\/li>\n<\/ul>\n<\/li>\n<li>Vulnerabiltiy Scanning with an Admission Controller<br \/>\n-Scanning<\/p>\n<ul>\n<li>Tip 1: Admission controllers intercept requests to the Kubernetes API before objects are created.  They can allow objects to be created, they can prevent the creation of those objects, or make changes to objects before creating them.<\/li>\n<li>Tip 2: The ImagePolicyWebhook admission controller allows you to use customizable logic to approve or deny the creation of workloads based upon the container images being used.<\/li>\n<li>Tip 3: You can use the ImagePolicyWebhook admission controller to have an external application scan images for vulnerabilities automatically as workloads are created.\n<ul>\n<li>Set up and Image Server<\/li>\n<\/ul>\n<\/li>\n<li>Tip 1: First, the ImagePolicyWebhook admission controller sends a JSON request to an external service to determine if images are allowed.<\/li>\n<li>Tip 2: The external service provides a JSON response indicating whether the images are allowed or disallowed.\n<ul>\n<li>Configuring the ImagePolicyWebhook Admission Controller<\/li>\n<\/ul>\n<\/li>\n<li>Tip 1: Use the --enable-admission-plugins flag in the kube-apiserver manifest to enable the ImagePolicyWebhook admission controller.<\/li>\n<li>Tip 2: Use the --admission-control-config-file flag, also in that same manifest, to specify the location of the admission control configuration file.<\/li>\n<li>Tip 3: If the config files are on the host file system, you may need to mount them to the kube-apiserver container.<\/li>\n<li>Tip 4: In the admission control config file, the kubeConfigFile option specifies the location of a kubeconfig.  This kubeconfig file is what tells ImagePolicyWebhook how to reach the webhook backend.<\/li>\n<\/ul>\n<\/li>\n<\/ul>\n<h2>6.2. Images<\/h2>\n<p>see exam tips<\/p>\n<p><a href=\"https:\/\/kubernetes.io\/docs\/concepts\/security\/overview\/\">https:\/\/kubernetes.io\/docs\/concepts\/security\/overview\/<\/a><\/p>\n<h2>6.3. Whitelisting Registries<\/h2>\n<p>OPA Gatekeeper. ConstraintTemplate with rules and defining new Kind, and K8sAllowedRepos with actual whitelisting<\/p>\n<h3>6.3.1.1.1. k8sallowedrepos.yml<\/h3>\n<pre><code>apiVersion: templates.gatekeeper.sh\/v1beta1\nkind: ConstraintTemplate\nmetadata:\n name: k8sallowedrepossudo falco -r nginx-rules.yml -M 45 spec:\n  crd:\n    spec:\n      names:\n        kind: K8sAllowedRepos\n      validation:\n        # Schema for the `parameters` field\n        openAPIV3Schema:\n          properties:\n            repos:\n              type: array\n              items:\n                type: string\n  targets:\n    - target: admission.k8s.gatekeeper.sh\n    rego: |\n      package k8sallowedrepos\n      violation[{&quot;msg&quot;: msg}] {\n      container := input.review.object.spec.containers[_]\n        satisfied := [good | repo = input.parameters.repos[_] ; good = startswith(container.image,repo)]\n        not any(satisfied)\n        msg := sprintf(&quot;container &lt;%v&gt; has an invalid image repo &lt;%v&gt;, allowed repos are %v&quot;,[container.name, container.image, input.parameters.repos])\n      }\n      violation[{&quot;msg&quot;: msg}] {\n      container := input.review.object.spec.initContainers[_]\n        satisfied := [good | repo = input.parameters.repos[_] ; good = startswith(container.image,repo)]\n        not any(satisfied)\n        msg := sprintf(&quot;container &lt;%v&gt; has an invalid image repo &lt;%v&gt;, allowed repos are %v&quot;,[container.name, container.image, input.parameters.repos])\n}<\/code><\/pre>\n<h3>6.3.1.1.2. whitelist-dockerhub.yml<\/h3>\n<pre><code>apiVersion: constraints.gatekeeper.sh\/v1beta1\nkind: K8sAllowedRepos\nmetadata:\n  name: whitelist-dockerhub\nspec:\n  match:\n    kinds:\n    - apiGroups: [&quot;&quot;]\n      kinds: [&quot;Pod&quot;]\n  parameters:\n    repos:\n    - &quot;docker.io&quot;<\/code><\/pre>\n<h2>6.4. Image Validation<\/h2>\n<h2>6.5. Static Analysis<\/h2>\n<h3>6.5.1. Dockerfiles<\/h3>\n<p><a href=\"https:\/\/docs.docker.com\/engine\/reference\/builder\/\">https:\/\/docs.docker.com\/engine\/reference\/builder\/<\/a><\/p>\n<p>To look for in Dockerfiles:<\/p>\n<ol>\n<li>Avoid user root<\/li>\n<li>Avoid latest tag<\/li>\n<li>unnecessary Software<\/li>\n<li>Verify no sensitive Data<\/li>\n<\/ol>\n<h3>6.5.2. YAML files<\/h3>\n<p>Don't use:<\/p>\n<ol>\n<li>Host Namespaces (aka hostIPC, hostNetwork, hostPID)<\/li>\n<li>Privileged mode<\/li>\n<li>:latest  tag<\/li>\n<li>Run as root<\/li>\n<\/ol>\n<h2>6.6. Vulnerability Scanning<\/h2>\n<p>Use Trivy, documentation at <a href=\"https:\/\/github.com\/aquasecurity\/trivy\/blob\/main\/docs\/index.md\">https:\/\/github.com\/aquasecurity\/trivy\/blob\/main\/docs\/index.md<\/a><\/p>\n<p>Install via apt according to: <a href=\"https:\/\/github.com\/aquasecurity\/trivy\/blob\/main\/docs\/getting-started\/installation.md#debianubuntu\">https:\/\/github.com\/aquasecurity\/trivy\/blob\/main\/docs\/getting-started\/installation.md#debianubuntu<\/a><\/p>\n<p>for Linux Mint you have to use the UBUNTU_CODENAME so we can use this command to add the deb: <\/p>\n<pre><code>echo &quot;deb [signed-by=\/usr\/share\/keyrings\/trivy.gpg] https:\/\/aquasecurity.github.io\/trivy-repo\/deb&nbsp; $(cat \/etc\/os-release  | grep UBUNTU_CODENAME | awk -F&#039;[\/=]&#039; &#039;{ print $2}&#039;) main&quot; | sudo tee -a \/etc\/apt\/sources.list.d\/trivy.list<\/code><\/pre>\n<h3>6.6.1. get trivy running<\/h3>\n<ol>\n<li>create token at github, (see this issue for the why)\n<ol>\n<li><a href=\"https:\/\/github.com\/settings\/tokens\">https:\/\/github.com\/settings\/tokens<\/a><\/li>\n<li>Copy the token<\/li>\n<\/ol>\n<\/li>\n<li>Probably something more to install, because docker login does not work <a href=\"https:\/\/stackoverflow.com\/a\/74006782\/7311363\">https:\/\/stackoverflow.com\/a\/74006782\/7311363<\/a>\n<pre><code>sudo apt install golang-docker-credential-helpers<\/code><\/pre>\n<\/li>\n<li>\n<p>according to <a href=\"https:\/\/github.com\/aquasecurity\/trivy\/issues\/2373#issuecomment-1163355311\">https:\/\/github.com\/aquasecurity\/trivy\/issues\/2373#issuecomment-1163355311<\/a><\/p>\n<pre><code>export CR_PAT=ghp_NEW_TOKEN\necho $CR_PAT | docker login ghcr.io -u $USERNAME --password-stdin\nLogin Succeeded\n\ntrivy image alpine:latest\n\n# you can now check on other registries\ntrivy image quay.io\/vshn\/keycloak-theme:v1.4.0<\/code><\/pre>\n<\/li>\n<\/ol>\n<h3>6.6.2. some commands<\/h3>\n<p>find image from pods:<\/p>\n<pre><code># only for one specific pod\nkubectl -n questionablesoft get pod admin-web-host -o jsonpath=&#039;{..image}{&quot;\\n}&#039;\n\n# for all pods in a namespace\nkubectl -n questionablesoft get pods  -o jsonpath=&#039;{range .items[*]}{.containers}{&quot;\\n&quot;}{end}&#039;\n\n# get all images from a all namespace and log vulnerabilitiy to log file (and replace \/ in log file name\nkubectl get pod -A -o jsonpath=&#039;{range .items[*]}{..image}{&quot;\\n&quot;}{end}&#039; | awk &#039;{ print $1 }&#039; | xargs -I{} sh -c &#039;trivy image {} &gt; $(echo {} | sed &quot;s|\\\/|-|g&quot;).log&#039;\n# check which logs have critical vulnerabilites\ngrep -lre &quot;CRITICAL: [1-9]&quot;<\/code><\/pre>\n<h2>6.7. Vulnerabiltiy Scanning with an Admission Controller<\/h2>\n<p>how to turn on <a href=\"https:\/\/kubernetes.io\/docs\/reference\/access-authn-authz\/admission-controllers\/\">https:\/\/kubernetes.io\/docs\/reference\/access-authn-authz\/admission-controllers\/<\/a>, keyword is ImagePolicyWebhook<\/p>\n<p>some changes in \/etc\/kubernetes\/manifest\/kube-apiserver.yaml<\/p>\n<p>in the AdmissionConfiguration template we have a kubeConfigFile. In this file we need to configure the admission server for the checks. It must be with https<\/p>\n<h2>6.8. Copy from Lab<\/h2>\n<h3>6.8.1. Configure the Admission Controller<\/h3>\n<ol>\n<li>Edit the admission-control.conf file:<br \/>\n<code>sudo vi \/etc\/kubernetes\/admission-control\/admission-control.conf<\/code><\/li>\n<li>Paste in the ImagePolicyWebhook:<\/li>\n<\/ol>\n<pre><code>apiVersion: apiserver.config.k8s.io\/v1\nkind: AdmissionConfiguration\nplugins:\n- name: ImagePolicyWebhook\n  configuration:\n    imagePolicy:\n      kubeConfigFile: \/etc\/kubernetes\/admission-control\/imagepolicy_backend.kubeconfig\n      allowTTL: 50\n      denyTTL: 50\n      retryBackoff: 500\n      defaultAllow: false<\/code><\/pre>\n<h3>6.8.2. Backend Webhook<\/h3>\n<ol>\n<li>Edit the kubeconfig file:<br \/>\n<code>sudo vi \/etc\/kubernetes\/admission-control\/imagepolicy_backend.kubeconfig<\/code><\/li>\n<li>Set the location of the backend image scanning service:<br \/>\n<code>server: https:\/\/acg.trivy.k8s.webhook:8090\/scan<\/code><\/li>\n<li>To save and exit the file, press Escape, type :wq, and hit Enter.<\/li>\n<\/ol>\n<h3>6.8.3. Enable Any Necessary Admission Control Plugins<\/h3>\n<ol>\n<li>Edit the kube-apiserver manifest:<br \/>\n<code>sudo vi \/etc\/kubernetes\/manifests\/kube-apiserver.yaml<\/code><\/li>\n<li>In the command container, scroll down to --enable-admission-plugins and add ImagePolicyWebhook:<br \/>\n<code>--enable-admission-plugins=NodeRestriction,ImagePolicyWebhook<\/code><\/li>\n<li>To save and exit the file, press Escape, type :wq, and hit Enter.<\/li>\n<li>Once the kube-apiserver has been re-created, create the good-pod Pod:<br \/>\n<code>kubectl create -f good-pod.yml<\/code><br \/>\nThe Pod should be successfully created.<\/li>\n<li>Attempt to create the bad-pod Pod:<br \/>\n<code>kubectl create -f bad-pod.yml<\/code><br \/>\nPod creation should fail and return an error due to image vulnerabilities.<\/li>\n<\/ol>\n<h1>7. Monitoring, Logging, and Runtime Security<\/h1>\n<h2>7.1. Exam Tips Section 7<\/h2>\n<p>Source: acloud.guru course <\/p>\n<ul>\n<li>Bahvioral Analytics\n<ul>\n<li>Understanding Bahvioral Analytics\n<ul>\n<li>Tip 1: Behavioral analytics is the process of monitoring what's happening within a system to detect malicious activity.<\/li>\n<li>Tip 2: Secondly, one way to perform behavioral analytics in Kubernetes is to use tools like Falco.<\/li>\n<\/ul>\n<\/li>\n<li>Analyzing Container Behavior with Falco\n<ul>\n<li>Tip 1: You can run Falco from the command line with the falco command, and you can view Falco's options with falco --help.<\/li>\n<li>Tip 2: Use the -r flag to pass in a Falco rules file<\/li>\n<li>Tip 3: Use falco --list to see all available fields for conditions and outputs.<\/li>\n<li>Tip 4: Use the -M flag to set the number of seconds that Falco should collect data for.  (e.g. -M 45 to run for 45 seconds)<\/li>\n<\/ul>\n<\/li>\n<\/ul>\n<\/li>\n<li>Immutable Containers\n<ul>\n<li>Tip 1: Immutability means that containers do not change at runtime by downloading and running new code or changing their code in any other way.<\/li>\n<li>Tip 2: Containers that use privileged mode such as securityContext.privileged may also be considered mutable.<\/li>\n<li>Tip 3: Set a readOnlyRootFilesystem using container.securityContext.readOnlyRootFilesysstem to prevent a container from writing to its file system and therefore, help make that container immutable.<\/li>\n<li>Tip 4: If an application does need to write to files such as for caching or logging, you can use an emptyDir volume alongside readOnlyRootFilesystem for those locations where the application does actually need to write data.<\/li>\n<\/ul>\n<\/li>\n<li>Audit Logging\n<ul>\n<li>Understanding Audit Logging\n<ul>\n<li>Tip 1: Kubernetes auditing allows you to capture logs of all changes made through the Kubernetes API<\/li>\n<li>Tip 2: Your audit log policy rules, the level, identifies how detailed the log data should be for the rule.<\/li>\n<li>None - which logs nothing,$<\/li>\n<li>RequestResponse - which logs everything, including the request and response body.<\/li>\n<li>Request - logs only the request body, but not the response body.<\/li>\n<li>Metadata - logs only the basic high-level metadata about the request.<\/li>\n<li>Tip 3: In the audit log policy rules, that resources field identifies which Kubernetes resource types the rule applies to<\/li>\n<li>Tip 4: The namespaces field, which is optional, limits the rule to only specific namespaces.<\/li>\n<\/ul>\n<\/li>\n<li>Setting Up Audit Logging\n<ul>\n<li>Tip 1: Define audit rules in the audit policy configuration file<\/li>\n<li>Tip 2: kube-apiserver flags for audit logging in \/etc\/kubernetes\/manifests\/kube-apiserver.yaml:<\/li>\n<li>--audit-policy-file  - Points to the audit policy config file<\/li>\n<li>--audit-log-path  - Location of output files<\/li>\n<li>--audit-log-maxage  - The number of days to keep old log files<\/li>\n<li>--audit-log-maxbackup  - The number old log files to keep<\/li>\n<\/ul>\n<\/li>\n<\/ul>\n<\/li>\n<\/ul>\n<h2>7.2. Bahvioral Analytics<\/h2>\n<p>Official docs: <a href=\"https:\/\/falco.org\/docs\/\">https:\/\/falco.org\/docs\/<\/a><\/p>\n<p>Falco a tool for such analysis<\/p>\n<p>Falco can be run in cli with:<\/p>\n<pre><code># -r &lt;file&gt; to supply a custom rules file\n# -M &lt;seconds&gt; to run Falco for X seconds\n# falco should run on the worker where the container is runnig\nfalco -r rules.yml -M 45<\/code><\/pre>\n<h3>7.2.1. falco rules<\/h3>\n<p>example from Lab, see <a href=\"https:\/\/falco.org\/docs\/rules\/supported-fields\/\">https:\/\/falco.org\/docs\/rules\/supported-fields\/<\/a> for available fields<\/p>\n<pre><code>- rule: spawned_process_in_nginx_container\n  desc: A process was spawned in the Nginx container.\n  condition: container.name = &quot;nginx&quot; and evt.type = execve  and evt.dir=&lt;\n  output: &quot;Process Spawned, %evt.time.iso8601, %evt.datetime, %proc.name, %user.uid, %container.id, %container.name, %container.image&quot;\n  priority: WARNING<\/code><\/pre>\n<h2>7.3. Immutable Containers<\/h2>\n<p>Immutability:<\/p>\n<p>Use Volume Mounts if you want to write<\/p>\n<h3>7.3.1. how to check for immutability<\/h3>\n<ol>\n<li>use kubectl get pod $POD -o yaml  and check the spec section for Priviledge modes or R\/W filesystems\n<ol>\n<li>see securityContext:<\/li>\n<\/ol>\n<\/li>\n<li>something like that:\n<pre><code>spec:\n  containers:\n  - image: nginx:1.19.1\n    imagePullPolicy: IfNotPresent\n    name: nginx\n    resources: {}\n    securityContext:\n      allowPrivilegeEscalation: true\n      runAsUser: 0<\/code><\/pre>\n<\/li>\n<\/ol>\n<h2>7.4. Audit Logging<\/h2>\n<p><a href=\"https:\/\/kubernetes.io\/docs\/tasks\/debug\/debug-cluster\/audit\/\">https:\/\/kubernetes.io\/docs\/tasks\/debug\/debug-cluster\/audit\/<\/a><\/p>\n<h3>7.4.1. Lab notes<\/h3>\n<p>my basteling for \/etc\/kubernetes\/audit-policy.yaml, based on <a href=\"https:\/\/kubernetes.io\/docs\/tasks\/debug\/debug-cluster\/audit\/#audit-policy\">https:\/\/kubernetes.io\/docs\/tasks\/debug\/debug-cluster\/audit\/#audit-policy<\/a><\/p>\n<pre><code>apiVersion: audit.k8s.io\/v1\nkind: Policy\n# Don&#039;t generate audit events for all requests in RequestReceived stage.\nomitStages:\n  - &quot;RequestReceived&quot;\nrules:\n# Log request and response bodies for all changes to namespaces.\n  - level: RequestResponse\n    resources:\n    - group: &quot;&quot;\n      resources: [&quot;namespaces&quot;]\n# Log request bodies (but not response bodies) for changes to Pods and Services in the web namespace.\n  - level: Request\n    resources:\n    - group: &quot;&quot;\n      resources: [&quot;pods&quot;, &quot;services&quot;]\n    namespaces: [&quot;web&quot;]\n# Log metadata for all changes to Secrets.\n  - level: Metadata\n    resources:\n    - group: &quot;&quot; # core API group\n      resources: [&quot;secrets&quot;]\n\n# A catch-all rule to log all other requests at the Metadata level.\n  - level: Metadata<\/code><\/pre>\n<p>Edit kube-apiserver flags for audit logging in \/etc\/kubernetes\/manifests\/kube-apiserver.yaml:<\/p>\n<pre><code>- command:\n  - kube-apiserver\n  - ...\n  - --audit-policy-file=\/etc\/kubernetes\/audit-policy.yaml\n  - --audit-log-path=\/var\/log\/kubernetes\/k8s-audit.log\n  - --audit-log-maxage=60\n  - --audit-log-maxbackup=1<\/code><\/pre>\n<h1>Acloud.Guru Lab01 - Service Account<\/h1>\n<h2>Fix Pod's Service Account<\/h2>\n<p>my basteling:<\/p>\n<pre><code>cloud_user@k8s-cli:~\/lab01$ cat buffy-role-sa.yml\napiVersion: rbac.authorization.k8s.io\/v1\nkind: Role\nmetadata:\n  name: buffy-role\n  namespace: sunnydale\nrules:\n- apiGroups: [&quot;&quot;]\n  resources: [&quot;pods&quot;]\n  verbs: [&quot;list&quot;]\n\ncloud_user@k8s-cli:~\/lab01$ cat buffy-sa-watch-rb.yml\napiVersion: rbac.authorization.k8s.io\/v1\nkind: RoleBinding\nmetadata:\n  name: buffy-sa-watch-rb\n  namespace: sunnydale\nsubjects:\nroleRef:\n  apiGroup: rbac.authorization.k8s.io\n  kind: Role\n  name: watch-services-secrets\nsubjects:\n- kind: ServiceAccount\n  name: buffy-sa\n  namespace: sunnydale\n\ncloud_user@k8s-cli:~\/lab01$ cat watch-services-secrets.yml\napiVersion: rbac.authorization.k8s.io\/v1\nkind: Role\nmetadata:\n  name: watch-services-secrets\n  namespace: sunnydale\nrules:\n- apiGroups: [&quot;&quot;]\n  resources: [&quot;services&quot;, &quot;secrets&quot;]\n  verbs: [&quot;watch&quot;]<\/code><\/pre>\n<h2>Fix a Pod Configure to Use Incorrect SA<\/h2>\n<p>my basteling<\/p>\n<pre><code>cloud_user@k8s-cli:~\/lab01-2$ cat kaput-lando.yml\napiVersion: v1\nkind: ServiceAccount\nmetadata:\n  creationTimestamp: &quot;2022-11-23T17:23:42Z&quot;\n  name: lando\n  namespace: bespin\n  resourceVersion: &quot;727&quot;\n  uid: 9027d6e7-ba08-4863-9a96-722c020c883a\n\ncloud_user@k8s-cli:~\/lab01-2$ cat lando-sa.yml\napiVersion: v1\nkind: ServiceAccount\nmetadata:\n  name: lando-sa\n  namespace: bespin\nautomountServiceAccountToken: false\n\ncloud_user@k8s-cli:~\/lab01-2$ cat lando.yml\napiVersion: v1\nkind: Pod\nmetadata:\n  name: lando\n  namespace: bespin\nspec:\n  serviceAccountName: lando-sa\n  containers:\n  - name: busybox\n    image: busybox:1.33.1\n    command: [&#039;sh&#039;, &#039;-c&#039;, &#039;while true; do sleep 5; done&#039;]<\/code><\/pre>\n<h1>Acloud.Guru Lab02 \u2013 Control Plane<\/h1>\n<h2>broken control plane<\/h2>\n<p>edit on \/var\/lib\/kubelet\/config.yaml (not \/etc\/kubernetes\/manifests\/kube-apiserver.yaml as one could mean)<\/p>\n<pre><code>apiVersion: kubelet.config.k8s.io\/v1beta1\nauthentication:\n  anonymous:\n    enabled: false\n...\n authorization:\n    mode: Webhook<\/code><\/pre>\n<h2>second question profiling<\/h2>\n<p>now we have \/etc\/kubernetes\/manifests\/kube-apiserver.yaml <\/p>\n<pre><code>spec:\n  containers:\n  - command:\n    - kube-apiserver\n...\n    - --authorization-mode=Node,RBAC\n    - --profiling=false<\/code><\/pre>\n<p>third question - etcd<\/p>\n<pre><code>\/etc\/kubernetes\/etcd.yaml\nspec:\n  containers:\n  - command:\n    - etcd\n    - --advertise-client-urls=https:\/\/10.0.1.101:2379\n    - --cert-file=\/etc\/kubernetes\/pki\/etcd\/server.crt\n    - --client-cert-auth=true<\/code><\/pre>\n<h1>Acloud.Gur Lab 03 \u2013 Network Policy<\/h1>\n<p>Default deny Network Policy<\/p>\n<p>\u2192 <strong>below actually wrong:<\/strong> no &quot;Egress&quot; needed, they only talk about ingress<\/p>\n<pre><code>apiVersion: networking.k8s.io\/v1\nkind: NetworkPolicy\nmetadata:\n  name: default-deny\n  namespace: mordor\nspec:\n  podSelector: {}\n  policyTypes:\n  - Ingress\n  - Egress\n\ncreate NetworkPolicy\n\nuse k -n mordor get pods mtdoom --show-labels  to show labels directly\n\nfor the second selector they say, we should add &quot;namespaceSelector: {}&quot; to allow traffic from all namespaces.\n\nensure for the second rule you also have the &quot;-&quot;, so it an OR.\napiVersion: networking.k8s.io\/v1\nkind: NetworkPolicy\nmetadata:\n  name: mtdoom-np\n  namespace: mordor\nspec:\n  podSelector:\n    matchLabels:\n      app: mtdoom\n  policyTypes:\n    - Ingress\n  ingress:\n  - from:\n    - namespaceSelector:\n        matchLabels:\n          app: frodo\n    - podSelector:\n        matchLabels:\n          app: sam\n      namespaceSelector: {}\n    ports:\n    - port: 80\n      protocol: TCP<\/code><\/pre>\n<h1>Acloud.Guru Lab04 - Image Policy<\/h1>\n<p>configure in separate file: \/etc\/kubernetes\/admission-control\/imagepolicy.conf<\/p>\n<pre><code>{\n   &quot;imagePolicy&quot;: {\n      &quot;kubeConfigFile&quot;: &quot;\/etc\/kubernetes\/admission-control\/imagepolicy_backend.kubeconfig&quot;,\n      &quot;allowTTL&quot;: 50,\n      &quot;denyTTL&quot;: 50,\n      &quot;retryBackoff&quot;: 500,\n      &quot;defaultAllow&quot;: false\n   }\n}<\/code><\/pre>\n<p><a href=\"https:\/\/acg.trivy.k8s.webhook:8090\/scan\">https:\/\/acg.trivy.k8s.webhook:8090\/scan<\/a> musst be added to \/etc\/kubernetes\/admission-control\/imagepolicy_backend.kubeconfig from kubeconfig file above<\/p>\n<p>For enabling:<\/p>\n<ul>\n<li>Open the kube-apiserver manifest for editing:<br \/>\n<code>sudo vi \/etc\/kubernetes\/manifests\/kube-apiserver.yaml<\/code><\/li>\n<li>In the --enable-admissions-plugin line under command, add our image policy webhook to the list:<br \/>\n<code>--enable-admissions-plugins=NodeRestriction,ImagePolicyWebhook<\/code><\/li>\n<\/ul>\n<h1>Acloud.Guru Lab 05 - Trivy<\/h1>\n<p>on control plane we could run it directly with:<\/p>\n<pre><code>kubectl get pods -n sunnydale -o jsonpath=&quot;{range .items[*]}{..image}{&#039;\\n&#039;}{end}&quot;  | cut -f1 -d&#039; &#039;  | xargs -I{} sh -c &#039;trivy image {} &gt;{}.log&#039;\n\negrep -l &quot;CRITICAL: [1-9]|HIGH: [1-9]&quot; *.log\n  centos:7.log\n  nginx:1.14.2.log\n\n# unfortunately the correlation to the pod has to be done manually\nk get pods -n sunnydale -o yaml | less\n\n# first is xander\n# second is cordelia\n\nk -n sunnydale delete  pods cordelia xander --force\n\n############## From Solution #############\n# direct way also including correlation\nkubectl get pods -n sunnydale --output=custom-columns=&quot;NAME:.metadata.name,IMAGE:.spec.containers[*].image&quot;<\/code><\/pre>\n<h1>Acloud.Guru Lab 06 - App Armor<\/h1>\n<p>AppArmor Profile enable<\/p>\n<ol>\n<li>Login to worker<\/li>\n<li>sudo apparmor_parser k8s-deny-write<\/li>\n<li>sudo cp k8s-deny-write \/etc\/apparmor.d\/ (to make it persistent)<\/li>\n<\/ol>\n<p>Pod with AppArmor profile:<\/p>\n<ol>\n<li>follow <a href=\"https:\/\/kubernetes.io\/docs\/tutorials\/security\/apparmor\/#example\">https:\/\/kubernetes.io\/docs\/tutorials\/security\/apparmor\/#example<\/a><\/li>\n<li>pod wit happarmor\n<pre><code>apiVersion: v1\nkind: Pod\nmetadata:\nname: chewbacca\nnamespace: kashyyyk\nannotations:\n# Tell Kubernetes to apply the AppArmor profile &quot;k8s-apparmor-example-deny-write&quot;.\n# annotation must have container name as key and the name of the apparmor rule (in the apparmor file) as value\ncontainer.apparmor.security.beta.kubernetes.io\/busybox: localhost\/k8s-deny-write\nspec:\ncontainers:\n- name: busybox\nimage: busybox:1.33.1\ncommand: [&#039;sh&#039;, &#039;-c&#039;, &#039;while true; do echo hunter2 &gt;&gt; password.txt; sleep 5; done&#039;<\/code><\/pre>\n<\/li>\n<li>apply  gives error\n<pre><code>k apply -f chewbacca.yml\nerror: error validating &quot;chewbacca.yml&quot;: error validating data: ValidationError(Pod.metadata): unknown field &quot;container.apparmor.security.beta.kubernetes.io\/busybox&quot; in io.k8s.apimachinery.pkg.apis.meta.v1.ObjectMeta; if you choose to ignore these errors, turn validation off with --validate=false<\/code><\/pre>\n<\/li>\n<\/ol>\n<h1>Acloud.Guru Lab 07 -  Falco<\/h1>\n<p>Container to monitor defined in condition<br \/>\nmonitor_rules.yml<\/p>\n<pre><code>- rule: something_spawned\n  desc: Spawned process\n  condition: container.name = &quot;monitor&quot; and evt.type = execve and evt.dir=&lt;\n  output: &quot;%evt.datetime,%container.id,%container.image,%user.uid,%proc.name&quot;\n  priority: NOTICE<\/code><\/pre>\n<p>solution is %evt.time instead of %evt.datetime, but that only prints the time without date, what is something hateful<\/p>\n<p>run rules:<\/p>\n<pre><code>cloud_user@k8s-worker1:~$ sudo falco -r monitor_rules.yml -M 45 &gt; falco_output.log\n\ncloud_user@k8s-worker1:~$ less falco_output.log\n07:09:12.524848344: Notice 2022-11-24 07:09:12.524848344,393544c622a5,docker.io\/library\/busybox:1.33.1,0,cat\n07:09:12.525215915: Notice 2022-11-24 07:09:12.525215915,393544c622a5,docker.io\/library\/busybox:1.33.1,0,sleep\nEvents detected: 2\nRule counts by severity:\n   NOTICE: 2\nTriggered rules by rule name:\n   something_spawned: 2<\/code><\/pre>\n<p>Some falco rules used on Killer.sh:<\/p>\n<pre><code># The explicit quotes are needed to avoid the - characters being\n# interpreted by the filter expression.\n- list: rpm_binaries\n  items: [dnf, rpm, rpmkey, yum, &#039;&quot;75-system-updat&quot;&#039;, rhsmcertd-worke, rhsmcertd, subscription-ma,\n          repoquery, rpmkeys, rpmq, yum-cron, yum-config-mana, yum-debug-dump,\n          abrt-action-sav, rpmdb_stat, microdnf, rhn_check, yumdb]\n\n- list: openscap_rpm_binaries\n  items: [probe_rpminfo, probe_rpmverify, probe_rpmverifyfile, probe_rpmverifypackage]\n\n- macro: rpm_procs\n  condition: (proc.name in (rpm_binaries, openscap_rpm_binaries) or proc.name in (salt-minion))\n\n- list: deb_binaries\n  items: [dpkg, dpkg-preconfigu, dpkg-reconfigur, dpkg-divert, apt, apt-get, aptitude,\n    frontend, preinst, add-apt-reposit, apt-auto-remova, apt-key,\n    apt-listchanges, unattended-upgr, apt-add-reposit, apt-config, apt-cache, apt.systemd.dai\n    ]\n- list: package_mgmt_binaries\n  items: [rpm_binaries, deb_binaries, update-alternat, gem, pip, pip3, sane-utils.post, alternatives, chef-client, apk, snapd]\n\n- macro: package_mgmt_procs\n  condition: proc.name in (package_mgmt_binaries)\n\n- macro: container\n  condition: container.id != host\n\n- macro: spawned_process\n  condition: evt.type = execve and evt.dir=&lt;\n\n- rule: kill_process\n  desc: kill_process\n  #condition: spawned_process and container and package_mgmt_procs\n  #condition: spawned_process and container and package_mgmt_procs and container.image contains &quot;nginx&quot;\n  condition: evt.type = kill and container\n  #condition: spawned_process and container and container.image = &quot;nginx&quot; and package_mgmt_binaries\n  output: &quot;%evt.time,%container.id,%container.name,%user.name -- %k8s.deployment.name, %k8s.pod.name&quot;\n  priority: WARNING\n\n- rule: nginx_image_is_running\n  desc: nginx image with apt\n  #condition: spawned_process and container and package_mgmt_procs\n  condition: spawned_process and container and package_mgmt_procs and container.image contains &quot;nginx&quot;\n  #condition: spawned_process and container and container.image = &quot;nginx&quot; and package_mgmt_binaries\n  output: &quot;%evt.time,%container.id,%container.name,%user.name&quot;\n  priority: WARNING<\/code><\/pre>\n<h1>Acloud.Guru Lab 08 - Audit Logging<\/h1>\n<p>Create rules, there are good examples at <a href=\"https:\/\/kubernetes.io\/docs\/tasks\/debug\/debug-cluster\/audit\/#log-backend\">https:\/\/kubernetes.io\/docs\/tasks\/debug\/debug-cluster\/audit\/#log-backend<\/a><\/p>\n<p>\/etc\/kubernetes\/audit-policy.yaml<\/p>\n<pre><code>apiVersion: audit.k8s.io\/v1\nkind: Policy\nomitStages:\n  - &quot;RequestReceived&quot;\nrules:\n  - level: None\n    resources:\n    - group: &quot;&quot;\n      resources: [&quot;pods\/log&quot;, &quot;pods\/status&quot;]\n  - level: RequestResponse\n    resources:\n    - group: &quot;&quot;\n      resources: [&quot;configmaps&quot;]\n  - level: Request\n    resources:\n    - group: &quot;&quot;\n      resources: [&quot;services&quot;, &quot;pods&quot;]\n    namespaces: [&quot;web&quot;]\n  - level: Metadata\n    resources:\n    - group: &quot;&quot;\n      resources: [&quot;secrets&quot;]\n  # A catch-all rule to log all other requests at the Metadata level.\n  - level: Metadata<\/code><\/pre>\n<p>You could follow <a href=\"https:\/\/kubernetes.io\/docs\/tasks\/debug\/debug-cluster\/audit\/#log-backend\">https:\/\/kubernetes.io\/docs\/tasks\/debug\/debug-cluster\/audit\/#log-backend<\/a><\/p>\n<p>Add values to \/etc\/kubernetes\/manifests\/kube-apiserver.yaml<\/p>\n<pre><code>spec:\n  containers:\n  - command:\n    - kube-apiserver\n    - --audit-policy-file=\/etc\/kubernetes\/audit-policy.yaml\n    - --audit-log-path=\/var\/log\/kubernetes\/audit.log\n    - --audit-log-maxage=10\n    - --audit-log-maxbackup=1<\/code><\/pre>\n<p>The volumes are already mounted, but would have been straight forward with the documentation.<\/p>\n<h1>Acloud.Guru Lab 09 - Secrets<\/h1>\n<p>jsonpath docu on k8s docs is cool<\/p>\n<pre><code>cloud_user@k8s-cli:~$ k get secrets -n larry curly\nNAME    TYPE     DATA   AGE\ncurly   Opaque   2      71m\ncloud_user@k8s-cli:~$ k get secrets -n larry curly -o yaml\napiVersion: v1\ndata:\n  password: MTIzNDUK\n  username: YWRtaW4K\nkind: Secret\nmetadata:\n  creationTimestamp: &quot;2022-11-24T06:38:08Z&quot;\n  name: curly\n  namespace: larry\n  resourceVersion: &quot;608&quot;\n  uid: ba44fc94-2159-4455-acfd-de69634dc3bf\ntype: Opaque\n\ncloud_user@k8s-cli:~$ kubectl -n larry get secrets -o=jsonpath=&#039;{range .items[*]}{.metadata.name}{&quot;\\tusername=&quot;}{.data.username}{&quot;\\tpassword=&quot;}{.data.password}{&quot;\\n&quot;}{end}&#039;\ncurly   username=YWRtaW4K   password=MTIzNDUK\n\ncloud_user@k8s-cli:~$ kubectl -n larry get secrets curly -o=jsonpath=&#039;{.data.username}&#039; | base64 --decode\nadmin\ncloud_user@k8s-cli:~$ kubectl -n larry get secrets curly -o=jsonpath=&#039;{.data.password}&#039; | base64 --decode\n12345\n\n# save them directly:\ncloud_user@k8s-cli:~$ kubectl -n larry get secrets curly -o=jsonpath=&#039;{.data.username}&#039; | base64 --decode &gt; username.txt\ncloud_user@k8s-cli:~$ kubectl -n larry get secrets curly -o=jsonpath=&#039;{.data.password}&#039; | base64 --decode &gt; password.txt<\/code><\/pre>\n<p>you can convert to base in ViM direct and insert it to a secret <code>:read !sh -c &#039;echo dbuser | base64&#039;<\/code><\/p>\n<p>moe.yml and secret-pod.yml<\/p>\n<pre><code>---\napiVersion: v1\nkind: Secret\ndata:\n  password: QTgzTWFlS296Cg==\n  username: ZGJ1c2VyCg==\nmetadata:\n  name: moe\n  namespace: larry\ntype: Opaque\n\n---\napiVersion: v1\nkind: Pod\nmetadata:\n  name: secret-pod\n  namespace: larry\nspec:\n  containers:\n  - name: busybox\n    image: busybox:1.33.1\n    command: [&#039;sh&#039;, &#039;-c&#039;, &#039;cat \/etc\/credentials\/username; cat \/etc\/credentials\/password; while true; do sleep 5; done&#039;]\n    volumeMounts:\n    - name: secret-volume\n      readOnly: true\n      mountPath: &quot;\/etc\/credentials&quot;\n  volumes:\n  - name: secret-volume\n    secret:\n      secretName: moe\ncloud_user@k8s-cli:~$<\/code><\/pre>\n<p>verify <\/p>\n<pre><code>cloud_user@k8s-cli:~$ k -n larry exec secret-pod -- sh -c &#039;cat  \/etc\/credentials\/*&#039;\nA83MaeKoz\ndbuser<\/code><\/pre>\n<h1>Acloud.Guru Lab 10 - Analyzing Dockerfile and YAML<\/h1>\n<p>Dockerfile fix<\/p>\n<pre><code>cloud_user@k8s-cli:~$ diff Dockerfile*\n1c1\n&lt; FROM alpine:3.13.5\n---\n> FROM alpine:latest\n6c6\n&lt; USER nobody\n---\n> USER root<\/code><\/pre>\n<p>YAML fixing<\/p>\n<pre><code>cloud_user@k8s-cli:~$ diff scooby-gang-deploy.yml*\n20,21c20,21\n&lt;           privileged: false\n&lt;           runAsUser: 65534\n---\n>           privileged: true\n>           runAsUser: 0<\/code><\/pre>\n<p>find mutable\/immutable containers<\/p>\n<pre><code># browse throu all pods in the namespace\nk -n sunnydale get pods -o yaml | less\n\n### looks like Pod &quot;buffy&quot; and &quot;xander&quot; ar mutable:\n      securityContext:\n        allowPrivilegeEscalation: false\n        runAsUser: 0\n...\n      securityContext:\n        allowPrivilegeEscalation: false\n        readOnlyRootFilesystem: false\n\n# delete the bad pods\n\nk -n sunnydale delete pods buffy xander --force<\/code><\/pre>\n<h1>Acloud.Guru Lab 11 - gVisor<\/h1>\n<p>sandbox.yml<\/p>\n<pre><code>apiVersion: node.k8s.io\/v1\nkind: RuntimeClass\nmetadata:\n  name: sandbox\nhandler: runsc<\/code><\/pre>\n<p>looks like runsc already is installed:<\/p>\n<pre><code>on control plane server\ncloud_user@k8s-control:~$ sudo grep runsc -A1 \/etc\/containerd\/config.toml\n        [plugins.&quot;io.containerd.grpc.v1.cri&quot;.containerd.runtimes.runsc]\n          runtime_type = &quot;io.containerd.runsc.v1&quot;<\/code><\/pre>\n<p>some notes to find out where to change the runtime:<\/p>\n<pre><code>cloud_user@k8s-control:~$ k -n sunnydale get pods\nNAME                     READY   STATUS    RESTARTS   AGE\nbuffy-5c9f5f7d54-vqhbc   1\/1     Running   0          143m\ngiles-5c9f5f7d54-s8nx7   1\/1     Running   0          143m\nspike-5c9f5f7d54-dvddg   1\/1     Running   0          143m\ncloud_user@k8s-control:~$ k -n sunnydale get all\nNAME                         READY   STATUS    RESTARTS   AGE\npod\/buffy-5c9f5f7d54-vqhbc   1\/1     Running   0          143m\npod\/giles-5c9f5f7d54-s8nx7   1\/1     Running   0          143m\npod\/spike-5c9f5f7d54-dvddg   1\/1     Running   0          143m\n\nNAME                    READY   UP-TO-DATE   AVAILABLE   AGE\ndeployment.apps\/buffy   1\/1     1            1           143m\ndeployment.apps\/giles   1\/1     1            1           143m\ndeployment.apps\/spike   1\/1     1            1           143m\n\nNAME                               DESIRED   CURRENT   READY   AGE\nreplicaset.apps\/buffy-5c9f5f7d54   1         1         1       143m\nreplicaset.apps\/giles-5c9f5f7d54   1         1         1       143m\nreplicaset.apps\/spike-5c9f5f7d54   1         1         1       143m  \n\n# check kernel running\ncloud_user@k8s-control:~$ k -n sunnydale exec buffy-5c9f5f7d54-vqhbc -- uname -a\nLinux buffy-5c9f5f7d54-vqhbc 5.13.0-1025-aws #27~20.04.1-Ubuntu SMP Thu May 19 15:17:13 UTC 2022 x86_64 GNU\/Linux\ncloud_user@k8s-control:~$ k -n sunnydale exec giles-5c9f5f7d54-s8nx7 -- uname -a\nLinux giles-5c9f5f7d54-s8nx7 5.13.0-1025-aws #27~20.04.1-Ubuntu SMP Thu May 19 15:17:13 UTC 2022 x86_64 GNU\/Linux\ncloud_user@k8s-control:~$ k -n sunnydale exec spike-5c9f5f7d54-dvddg -- uname -a\nLinux spike-5c9f5f7d54-dvddg 5.13.0-1025-aws #27~20.04.1-Ubuntu SMP Thu May 19 15:17:13 UTC 2022 x86_64 GNU\/Linux<\/code><\/pre>\n<p>Edit the deployments and add spec to the container spce:<\/p>\n<pre><code>k -n sunnydale edit deployments.apps buffy\n\n# edit the yaml at spec\n 33     spec:\n 34       runtimeClassName: sandbox\n 35       containers:\n 36       - command:\n\n#### verify\n\nkubectl get -n sunnydale pods -o=jsonpath=&#039;{range .items[*]}{.metadata.name}{&quot;\\n&quot;}{end}&#039; | xargs -I {} bash -c &#039;kubectl -n sunnydale exec {} -- uname -a&#039;\nLinux buffy-6ddc7d454-7vh7s 4.4.0 #1 SMP Sun Jan 10 15:06:54 PST 2016 x86_64 GNU\/Linux\nLinux giles-6ddc7d454-swp5w 4.4.0 #1 SMP Sun Jan 10 15:06:54 PST 2016 x86_64 GNU\/Linux\nLinux spike-6ddc7d454-9n74c 4.4.0 #1 SMP Sun Jan 10 15:06:54 PST 2016 x86_64 GNU\/Linux\n\n# with gVisor dmesg work, you could verify in one step with:\ncloud_user@k8s-cli:~$ kubectl get -n sunnydale pods -o=jsonpath=&#039;{range .items[*]}{.metadata.name}{&quot;\\n&quot;}{end}&#039; | xargs -I {} bash -c &#039;echo {}; kubectl -n sunnydale exec {} -- sh -c &quot;dmesg | head -2&quot;&#039;\nbuffy-6ddc7d454-7vh7s\n[   0.000000] Starting gVisor...\n[   0.166268] Generating random numbers by fair dice roll...\ngiles-6ddc7d454-swp5w\n[   0.000000] Starting gVisor...\n[   0.555445] Searching for socket adapter...\nspike-6ddc7d454-9n74c\n[   0.000000] Starting gVisor...\n[   0.388231] Preparing for the zombie uprising...<\/code><\/pre>\n<h1>Acloud.Guru Lab 12 - Pod Security Policy<\/h1>\n<p><a href=\"https:\/\/v1-24.docs.kubernetes.io\/docs\/concepts\/security\/pod-security-policy\/\">https:\/\/v1-24.docs.kubernetes.io\/docs\/concepts\/security\/pod-security-policy\/<\/a><\/p>\n<pre><code>PodSecurityPolicy\napiVersion: policy\/v1beta1\nkind: PodSecurityPolicy\nmetadata:\n  name: nopriv-psp\nspec:\n  privileged: false\n  runAsUser:\n    rule: RunAsAny\n  fsGroup:\n    rule: RunAsAny\n  seLinux:\n    rule: RunAsAny\n  supplementalGroups:\n    rule: RunAsAny\n  volumes:\n  - &#039;*&#039;<\/code><\/pre>\n<p>Use the policy:<\/p>\n<pre><code>cloud_user@k8s-cli:~$ kubectl create sa -n hoth hoth-sa\n\n## Cluster Role\n\ncloud_user@k8s-cli:~$  cat use-nopriv-psp.yml\napiVersion: rbac.authorization.k8s.io\/v1\nkind: ClusterRole\nmetadata:\n  name: use-nopriv-psp\nrules:\n- apiGroups: [&#039;policy&#039;]\n  resources: [&#039;podsecuritypolicies&#039;]\n  verbs:     [&#039;use&#039;]\n  resourceNames: [&#039;nopriv-psp&#039;]\n\ncloud_user@k8s-cli:~$ k create -f use-nopriv-psp.yml\nclusterrole.rbac.authorization.k8s.io\/use-nopriv-psp created\n\ncloud_user@k8s-cli:~$ cat hoth-sa-use-nopriv-psp.yml\n\n### Role Binding\n\ncloud_user@k8s-cli:~$ cat hoth-sa-use-nopriv-psp.yml\napiVersion: rbac.authorization.k8s.io\/v1\nkind: ClusterRoleBinding\nmetadata:\n  name: hoth-sa-use-nopriv-psp\nroleRef:\n  kind: ClusterRole\n  name: use-nopriv-psp\n  apiGroup: rbac.authorization.k8s.io\nsubjects:\n# Authorize specific service accounts (not recommended):\n- kind: ServiceAccount\n  name: hoth-sa\n  namespace: hoth\n\ncloud_user@k8s-cli:~$ k create -f hoth-sa-use-nopriv-psp.yml\nclusterrolebinding.rbac.authorization.k8s.io\/hoth-sa-use-nopriv-psp create\n\n### test\ncloud_user@k8s-cli:~$ k create -f luke.yml\nError from server (Forbidden): error when creating &quot;luke.yml&quot;: pods &quot;luke&quot; is forbidden: PodSecurityPolicy: unable to admit pod: [spec.containers[0].securityContext.privileged: Invalid value: true: Privileged containers are not allowed]<\/code><\/pre>\n<h1>killer.sh<\/h1>\n<p>there are some exerciese you have to use crictl, check it out on the docs<\/p>\n","protected":false},"excerpt":{"rendered":"<p>General Cheatsheet official cheat sheet https:\/\/kubernetes.io\/docs\/reference\/kubectl\/cheatsheet\/, here some favourites of mine, not only CKS specific. # `tail -f` pod kubectl logs my-pod &#8211;tail=10 -f # create yaml from image kubectl -n mynamespace run mynginx &#8211;dry-run=client &#8211;image=nginx:1.14 -o yaml &gt; mynginx.yml # permanently save the namespace for all subsequent kubectl commands in that context. kubectl config&#8230; <a href=\"https:\/\/blog.chloesoe.ch\/?p=813\" class=\"more-link\">Continue reading <span class=\"screen-reader-text\">CKS Notes<\/span><\/a><\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[1,20],"tags":[32,33],"class_list":["post-813","post","type-post","status-publish","format-standard","hentry","category-general","category-k8s","tag-cka","tag-cks"],"_links":{"self":[{"href":"https:\/\/blog.chloesoe.ch\/index.php?rest_route=\/wp\/v2\/posts\/813","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/blog.chloesoe.ch\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/blog.chloesoe.ch\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/blog.chloesoe.ch\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/blog.chloesoe.ch\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=813"}],"version-history":[{"count":6,"href":"https:\/\/blog.chloesoe.ch\/index.php?rest_route=\/wp\/v2\/posts\/813\/revisions"}],"predecessor-version":[{"id":819,"href":"https:\/\/blog.chloesoe.ch\/index.php?rest_route=\/wp\/v2\/posts\/813\/revisions\/819"}],"wp:attachment":[{"href":"https:\/\/blog.chloesoe.ch\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=813"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/blog.chloesoe.ch\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=813"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/blog.chloesoe.ch\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=813"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}