avatarTeri Radichel

Free AI web copilot to create summaries, insights and extended knowledge, download it at here

9845

Abstract

<div id="017c"><pre><span class="hljs-built_in">echo</span> <span class="hljs-string">'deb [signed-by=/etc/apt/keyrings/kubernetes-apt-keyring.gpg] https://pkgs.k8s.io/core:/stable:/v1.28/deb/ /'</span> | \ sudo <span class="hljs-built_in">tee</span> /etc/apt/sources.list.d/kubernetes.list</pre></div><p id="962b"><b>4. Update the package manager and install Kubernetes tools / CP-W</b></p><div id="1e40"><pre>sudo apt update sudo apt-get install -y kubelet kubeadm kubectl sudo apt-mark hold kubelet kubeadm kubectl</pre></div><p id="c402">At this point, we have installed all the necessary Kubernetes tools. Kubernetes services such as API server and kube-scheduler are running as containers. Also, pods we deploy run as containers. Therefore, we need a platform to manage these containers. Although Docker is the most popular container runtime, Kubernetes has recently switched to containerd as the default runtime. While Docker or CRI-O can still be configured as the runtime, this tutorial will focus on the containerd runtime</p><h2 id="abfe">Install containerd runtime</h2><p id="4f5d">If you are starting over with this tutorial, verify whether the overlay and br_netfilter kernel modules are loaded. If not, load them as we discussed earlier</p><div id="0b93"><pre>lsmod | grep <span class="hljs-string">"overlay\|br_netfilter"</span></pre></div><p id="8e80"><b>1. Add containerd repository key and add the repository to source list / CP-W</b></p><div id="b96d"><pre>curl -fsSL https://download.docker.com/linux/ubuntu/gpg | \ sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg</pre></div><div id="2434"><pre>sudo <span class="hljs-built_in">chmod</span> a+r /etc/apt/keyrings/docker.gpg</pre></div><div id="a513"><pre><span class="hljs-built_in">echo</span> \ <span class="hljs-string">"deb [arch="</span>$(dpkg --print-architecture)<span class="hljs-string">" signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/ubuntu \ "</span>$(. /etc/os-release &amp;&amp; <span class="hljs-built_in">echo</span> <span class="hljs-string">"<span class="hljs-variable">$VERSION_CODENAME</span>"</span>)<span class="hljs-string">" stable"</span></pre></div><div id="b18d"><pre>sudo <span class="hljs-built_in">tee</span> /etc/apt/sources.list.d/docker.list &gt; /dev/null</pre></div><p id="d5e1"><b>2. Install containerd / CP-W</b></p><div id="78b8"><pre>sudo apt update sudo apt install -y containerd.io</pre></div><p id="9a21"><b>3. Configure containerd / CP-W</b></p><p id="911c">Create a directory to store containerd config file in <i>/etc/</i></p><div id="192f"><pre>sudo <span class="hljs-built_in">mkdir</span> -p /etc/containerd</pre></div><p id="2667">Generate the default config toml file</p><div id="8ce2"><pre>sudo containerd config default|sudo <span class="hljs-built_in">tee</span> /etc/containerd/config.toml</pre></div><p id="bf32">Open the generated file in any text editor and verify whether the following settings are present. If not, you should set them as shown below</p><div id="145d"><pre><span class="hljs-section">[plugins."io.containerd.grpc.v1.cri".containerd.runtimes.runc]</span> <span class="hljs-attr">runtime_type</span> = <span class="hljs-string">"io.containerd.runc.v2"</span> <span class="hljs-comment"># &lt;- note this, this line might have been missed</span> <span class="hljs-section">[plugins."io.containerd.grpc.v1.cri".containerd.runtimes.runc.options]</span> <span class="hljs-attr">SystemdCgroup</span> = <span class="hljs-literal">true</span> <span class="hljs-comment"># &lt;- note this, this could be set as false in the default configuration, please make it true</span></pre></div><figure id="9d05"><img src="https://cdn-images-1.readmedium.com/v2/resize:fit:800/1*7HKoBp4oOiDO_uY_oGeTBQ.png"><figcaption>/etc/containerd/config.toml</figcaption></figure><p id="b5a7">Additionally, at the beginning of this config file, you should see the ‘disabled_plugins’ set as an empty list ([ ]). Please verify that it is indeed empty</p><figure id="a2f6"><img src="https://cdn-images-1.readmedium.com/v2/resize:fit:800/1*IvO8AMQISh4HyTESNPziXA.png"><figcaption>/etc/containerd/config.toml beginning</figcaption></figure><p id="8eaa">Now save the config file, close it and restart the containerd service</p><div id="ac5e"><pre>sudo systemctl restart containerd sudo systemctl <span class="hljs-built_in">enable</span> containerd systemctl status containerd</pre></div><figure id="0cba"><img src="https://cdn-images-1.readmedium.com/v2/resize:fit:800/1*D7OzjnDOmmrxvv-SvRWCKg.png"><figcaption>containerd running status</figcaption></figure><p id="39a1">At this point, our runtime installation and configuration setup is completed. However, it’s beneficial to have <i>crictl </i>for debugging purposes. You can use this tool to inspect running containerd containers, their status, and images. So, let’s configure crictl as well</p><p id="cf4c"><b>4. Setup <i>crictl </i>for inspecting containers / CP-W</b></p><p id="b44f">First run the below command and check the output</p><div id="9261"><pre> sudo crictl ps</pre></div><p id="26cf">If the <i>crictl </i>is not present, install it using the below command</p><div id="688f"><pre>sudo apt install cri-tools</pre></div><p id="dfad">Once the installation is completed, re-run the <i>sudo crictl ps </i>command. You may encounter output with errors and warnings. To address these issues, we need to add configurations for crictl. Additionally, you can customize the debug output using this config file</p><figure id="2371"><img src="https://cdn-images-1.readmedium.com/v2/resize:fit:800/1*TbSquSrZs4O_xrCX-Fnf5w.png"><figcaption>crictl output with errors and warnings</figcaption></figure><p id="ed53">Create <i>crictl.yaml</i> file in <i>/etc/</i></p><div id="b57f"><pre>sudo vim /etc/crictl.yaml</pre></div><p id="5fa8">Paste below content, save and exit</p><div id="e878"><pre><span class="hljs-attr">runtime-endpoint:</span> <span class="hljs-string">unix:///run/containerd/containerd.sock</span> <span class="hljs-attr">image-endpoint:</span> <span class="hljs-string">unix:///run/containerd/containerd.sock</span> <span class="hljs-attr">timeout:</span> <span class="hljs-number">2</span> <span class="hljs-attr">debug:</span> <span class="hljs-literal">true</span> <span class="hljs-comment"># &lt;- if you don't want to see debug info you can set this to false</span> <span class="hljs-attr">pull-image-on-create:</span> <span class="hljs-literal">false</span></pre></div><p id="10d5">Run the <i>sudo crictl ps </i>again<i>,</i>and you shouldn’t encounter any errors or warnings</p><figure id="f553"><img src="https://cdn-images-1.readmedium.com/v2/resize:fit:800/1*2iZeLqYd75K7Bt9v5SE_hg.png"><figcaption>crictl ps output with debug info enabled</figcaption></figure><p id="84e2">If you prefer not to see debug information, set the <i>debug </i>parameter to <i>false </i>in the <i>crictl.yaml</i> file</p><p id="b8c4">At this point, you won’t find any running containers. You can verify container images using the <i>sudo crictl images</i> command, and there won’t be any images present</p><p id="8cdd"><b>5. Enable <i>kubelet</i> service / CW-P</b></p><div id="9213"><pre>sudo systemctl <span class="hljs-built_in">enable</span> kubelet</pre></div><p id="3236">However, attempting to run the <i>kubelet </i>service will not be successful as the <i>kubectl configs</i> are missing. We won’t need to create these manually; they will be added to the system using <i>kubeadm </i>commands. Therefore, refrain from trying to start the <i>kubelet </i>service at this stage. Our current focus is on enabling the service only</p><p id="e746">Now it is time to initiate our control plane node</p><h1 id="bae5">Initializing Control-Plane Node</h1><p id="4583"><b>1. Run the below command and check for existing images / CP</b></p><div id="4f6d"><pre>sudo crictl images</pre></div><p id="fba3">You won’t find any images at this point as it’s a fresh installation</p><p id="21f5"><b>2. Pull necessary Kubernets images / CP</b></p><p id="c12f">We don’t have to perform this as an isolated process, but for the sake of verifying each small step, we’ll proceed with it separately</p><p id="d5eb">Run below command to pull images</p><div id="5855"><pre>sudo kubeadm config images pull --cri-socket unix:///var/run/containerd/containerd.sock</pre></div><figure id="8284"><img src="https://cdn-images-1.readmedium.com/v2/resize:fit:800/1*6TaZq5om-6_jEFC_E8vznA.png"><figcaption>Kubernets control-plane images</figcaption></figure><p id="6b1a">Now, if you execute the following command, you’ll see a list of containerd images</p><div id="e371"><pre>sudo crictl images</pre></div><figure id="4dfe"><img src="https://cdn-images-1.readmedium.com/v2/resize:fit:800/1*G73Enxk6tGtjfVBKUBykAQ.png"><figcaption></figcaption></figure><p id="b5e3">If you’re encountering extensive debug information, you can disable it as previously discussed in the crictl configuration section</p><p id="a638"><b>3. Initialize the control-plane / CP</b></p><p id="7e84"><b>This command will take some time to complete. Do not clear the output as you’ll need to refer to instructions from the command output</b></p><div id="714e"><pre>sudo kubeadm init \ --pod-network-cidr=10.244.0.0/16 \ --cri-socket unix:///var/run/containerd/containerd.sock \ --v=5</pre></div><p id="6906">If you have multiple container runtimes like Docker and containerd installed, you’ll need to specify the correct CRI socket. You can find these values in the official documentation. However, in our case, specifying the containerd socket should suffice</p><div id="0ecc" class="link-block"> <a href="https://kubernetes.io/docs/setup/production-environment/tools/kubeadm/install-kubeadm/#installing-runtime"> <div> <div> <h2>In # Options stalling kubeadm</h2> <div><h3>This page shows how to install the kubeadm toolbox. For information on how to create a cluster with kubeadm once you…</h3></div> <div><p>kubernetes.io</p></div> </div> <div> <div style="background-image: url(https://miro.readmedium.com/v2/resize:fit:320/0*2gI423xnb-J9AWUw)"></div> </div> </div> </a> </div><p id="3a5d">When selecting the pod-network-cidr range, choose a range that does not conflict with your network’s IP range</p><p id="ed94"><i>v=5</i> or higher would print verbose messages. This is useful when there are issues to fix</p><p id="a28d">At the end of the command output, you will see something like the following</p><figure id="3441"><img src="https://cdn-images-1.readmedium.com/v2/resize:fit:800/1*d_rhOFztJg9mSV4yThHyNA.png"><figcaption>kubeadm init output</figcaption></figure><p id="cf2e"><b>DO NOT skip the instruction in the beginning (1)</b>. Otherwise your <i>kubectl </i>won’t be connected with the API server. Even if you are running the cluster using the root user, you still need to follow this step. <i>kubectl </i>fetch the config from this location by default</p><p id="3915">error :</p><p id="ab4f"><i>couldn’t get current server API group list: Get “<a href="http://localhost:8080/api?timeout=32s">http://localhost:8080/api?timeout=32s</a>": dial tcp 127.0.0.1:8080: connect: connection refused</i></p><p id="b987"><i>The connection to the server localhost:8080 was refused — did you specify the right host or port?</i></p><figure id="3472"><img src="https://cdn-images-1.readmedium.com/v2/resize:fit:800/1*nmQDIdbnL8Ukxn2y2dKvmQ.png"><figcaption>kubectl won’t connect to API server even with root user if you haven’t done config copy as instructed</figcaption></figure><p id="2409">You will need the kubeadm join command (2) to connect the worker node with the control plane. However, you can always generate this. We’ll generate a new join command later when connecting our worker node with the control plane node</p><p id="5809">Run below command to copy config. You should perform this as a normal user if you plan to run <i>kubectl </i>with a regular user account. If you intend to run kubectl as root, execute it under the root account</p><div id="be2a"><pre> <span class="hljs-built_in">mkdir</span> -p <span class="hljs-variable">$HOME</span>/.kube sudo <span class="hljs-built_in">cp</span> -i /etc/kubernetes/admin.conf <span class="hljs-variable">$HOME</span>/.kube/config sudo <span class="hljs-built_in">chown</span> $(<span class="hljs-built_in">id</span> -u):$(<span class="hljs-built_in">id</span> -g) <span class="hljs-variable">$HOME</span>/.kube/config</pre></div><p id="bca8">Now, if you run the command <i>kubectl get nodes</i>, it should work</p><p id="74d4">Run below <i>kubectl </i>command to get the cluster nodes</p><div id="1f4e"><pre>kubectl <span class="hljs-keyword">get</span> nodes</pre></div><figure id="504d"><img src="https://cdn-images-1.readmedium.com/v2/resize:fit:800/1*g9_alLqV7vdkQYecRLMUGQ.png"><figcaption>kubectl get nodes output</figcaption></figure><p id="5f61">Note that you can see the control-plane node here, but the status is not ready. We need to apply the CNI plugin to make this control-plane ready. Also, if you check the running containers using <i>crictl ps</i>, you should see something similar to the following</p><figure id="10f5"><img src="https://cdn-images-1.readmedium.com/v2/resize:fit:800/1*-1lPbsnrzK9gsxr3_O25XQ.png"><figcaption>crictl ps output for freshly initialized kubernets control-plane node without CNI plugin</figcaption></figure><p id="bf09">We are going to use <b>Weave Net</b> in this tutorial as our CNI plugin</p><p id="50d0"><b>4. Add network add-on / CP</b></p><p id="4ede">You can get the latest add-on apply command from here</p><div id="f104" class="link-block"> <a href="https://www.weave.works/docs/net/latest/kubernetes/kube-addon/#-installation"> <div> <div> <h2>Integrating Kubernetes via the Addon</h2> <div><h3>The following topics are discussed: Before installing Weave Net, you should make sure the following ports are not…</h3></div> <div><p>www.weave.works</p></div> </div> <div> <div style="background-image: url(https://miro.readmedium.com/v2/resize:fit:320/)"></div> </div> </div> </a> </div><p id="c282">or you can use below command</p><div id="9e2b"><pre>kubectl apply -f https://github.com/weaveworks/weave/releases/download/v2.8.1/weave-daemonset-k8s.yaml</pre></div><p id="9331">Once you run the above command and still see the control-plane node in Not Ready status check the <i>sudo</i> <i>crictl ps </i>output. If it shown as below,</p><figure id="c7ed"><img src="https://cdn-images-1.readmedium.com/v2/resize:fit:800/1*m1am9PLRazWwXwSRFYE5Tw.png"><figcaption>weave add-on no attempts</figcaption></figure><p id="4eb6">Just restart your control-plane server and check. <b>Before restarting your control-plane server, exercise caution</b>. If your node has a dynamic IP interface and its IP changes upon restarting, the control-plane may not function correctly. Kubernetes utilizes IP as a component to sign certificates for network security</p><p id="e3ad">You would now see there is one or more attempts and the control plane is ready</p><div id="fc25"><pre>sudo crictl ps</pre></div><figure id="6278"><img src="https://cdn-images-1.readmedium.com/v2/resize:fit:800/1*fpidOPp07ustv571k11rRg.png"><figcaption>weave add-on has added successfully</figcaption></figure><div id="9745"><pre>kubectl get nodes</pre></div><figure id="7a74"><img src="https://cdn-images-1.readmedium.com/v2/resize:fit:800/1*HuaU04lIBQuQ2kIWvewNSw.png"><figcaption>Kubernets control-plane node is ready</figcaption></figure><p id="7ad5">At this point, your control plane node is ready. Let’s proceed to configure the worker node</p><h1 id="16c4">Join the Worker Node to Kubernets Control-Plane</h1><p id="51e0">In this section, we’ll switch between the control plane and worker node to execute various commands. <b>Pay attention to the short codes for each</b></p><ol><li><b>Switch to the control-plane node and generate the join command / CP</b></li></ol><p id="069a">As you already know, during the initialization of the control-plane, there was a join command provided. You can use it instead of generating a new one. However, it’s advisable to generate a new one, considering that the token has a short lifespan</p><p id="a973">Use the below command in the control plane node to generate the join command</p><div id="bfb9"><pre>kubeadm token create --print-join-command</pre></div><p id="0f16">It would display something similar to the following in the console</p><p id="45d9"><i>kubeadm join 192.168.8.120:6443 — token dg67p7.wvt7n5zxx9pxbmaz — discovery-token-ca-cert-hash sha256:36f9eb64ef8a6d45254b8994108b0e3a56e856bcb3b07d46cd83554db4114490</i></p><p id="f869">Copy the entire command as we’ll need this to join the worker node with the control-plane.</p><p id="f78a"><b>2. Switch to the worker node and follow the below instructions / W</b></p><p id="ee75">Verify whether you’ve completed all the steps marked as <b>CP-W</b> or <b>W </b>in the previous sections</p><p id="a6ac">Execute the join command you copied from the control-plane console. You’ll receive something similar to the following</p><figure id="0357"><img src="https://cdn-images-1.readmedium.com/v2/resize:fit:800/1*IK0cU5NQu4-AgYam6KCvZw.png"><figcaption>Kubernets worker node join command output</figcaption></figure><p id="8bab"><b>3. Switch back to the control-plane node and run the below command to verify / CP</b></p><div id="8db5"><pre>kubectl get nodes -o wide</pre></div><figure id="1221"><img src="https://cdn-images-1.readmedium.com/v2/resize:fit:800/1*FkXlBH-dmvAaxdc53rWwUA.png"><figcaption>kubectl output for get nodes -o wide command</figcaption></figure><p id="8f3f">Congratulations! At this stage, you have a functional minimum Kubernetes cluster</p><h1 id="22ee">What is Next?</h1><p id="1a87">You might want to explore this simple official documentation section on deploying a simple Nginx pod to your cluster</p><div id="4d13" class="link-block"> <a href="https://kubernetes.io/docs/tasks/run-application/run-stateless-application-deployment/"> <div> <div> <h2>Run a Stateless Application Using a Deployment</h2> <div><h3>This page shows how to run an application using a Kubernetes Deployment object. Objectives Create an nginx deployment…</h3></div> <div><p>kubernetes.io</p></div> </div> <div> <div style="background-image: url(https://miro.readmedium.com/v2/resize:fit:320/0*af-sBd8CqTyP8r6J)"></div> </div> </div> </a> </div><h1 id="1692">Needing some motivation to continue? Consider watching the following Honeypot documentary on Kubernetes</h1> <figure id="81bd"> <div> <div> <img class="ratio" src="http://placehold.it/16x9"> <iframe class="" src="https://cdn.embedly.com/widgets/media.html?src=https%3A%2F%2Fwww.youtube.com%2Fembed%2FBE77h7dmoQU&amp;display_name=YouTube&amp;url=https%3A%2F%2Fwww.youtube.com%2Fwatch%3Fv%3DBE77h7dmoQU&amp;image=http%3A%2F%2Fi.ytimg.com%2Fvi%2FBE77h7dmoQU%2Fhqdefault.jpg&amp;key=a19fcc184b9711e1b4764040d3dc5c07&amp;type=text%2Fhtml&amp;schema=youtube" allowfullscreen="" frameborder="0" height="480" width="854"> </div> </div> </figure></iframe></div></div></figure></article></body>

MFA on Delete For S3 Buckets

ACM.205 Requiring AWS principals to have MFA enabled to delete objects and versions

This is a continuation of my series of posts on Automating Cybersecurity Metrics, MFA, Passwords and S3 Buckets. The Code.

Free Content on Jobs in Cybersecurity | Sign up for the Email List

In the last post I wrote about how to enable Cost Management for an organization.

In this post, I’m going to jump back to a topic I meant to cover while writing about S3 buckets.

You may have noticed there were no permissions to delete objects or restrictions on deleting objects. One of the things we might want to enforce on all buckets is MFA delete on object versions.

There are a couple of ways we can enforce MFA delete on buckets. One is a setting on the bucket version configuration.

Why didn’t we configure this in our CloudFormation template? Because it’s not listed as an option in the CloudFormation documentation. According to the documentation we can enable this setting with the following command via the CLI.

aws s3api put-bucket-versioning --bucket DOC-EXAMPLE-BUCKET1 --versioning-configuration Status=Enabled,MFADelete=Enabled --mfa "SERIAL 123456"

The values for MFADelete are Enabled or Disabled.

In the command above it includes an mfa option. It appears in the documentation that this is optional.

The big caveat with MFA delete, however, is the following:

You cannot use MFA delete with lifecycle configurations. For more information about lifecycle configurations and how they interact with other configurations, see Lifecycle and other bucket configurations.

Since we added a lifecycle policy to our bucket, we cannot use MFA delete.

Bucket policies that enforce MFA

There is another way we can enforce MFA for deletion on bucket policies but only for specified users, or essentially we can whatever manages the lifecycle policy.

Per the documentation:

To enforce the MFA requirement, use the aws:MultiFactorAuthAge condition key in a bucket policy. 

Here’s the AWS sample code.

We can alter that to disallow getting or deleting the files without MFA.

{
    "Version": "2012-10-17",
    "Id": "123",
    "Statement": [
      {
        "Sid": "",
        "Effect": "Deny",
        "Principal": "*",
        "Action": [s3:delete,
                   s3:get]
        "Resource": "[bucket/*]",
        "Condition": { "Null": { "aws:MultiFactorAuthAge": true }}
      }
    ]
 }

Why does this example not just use the multi-factor is present condition instead of MultiFactorAuthAge? I don’t know.

IAM policies that enforce MFA

We can also enforce MFA on IAM policies, to ensure the principal taking actions is using MFA.

Caveats

We need to make sure the principal types that will require MFA for actions can use MFA, as I explained in prior posts.

For example, a role does not use MFA, but it requires MFA to assume a role.

If logged in from Okta currently the way I have it configured, MFA Is not required. We’ll revisit that later.

Due to all the caveats, I’m not going to enforce MFA delete in the bucket policy for now. I have something else to test related to Okta first. However, we can require MFA to assume a role and we can make sure that only the appropriate roles have permission to delete files or versions in buckets containing sensitive data.

Follow for updates.

Teri Radichel | © 2nd Sight Lab 2023

About Teri Radichel:
~~~~~~~~~~~~~~~~~~~~
⭐️ Author: Cybersecurity Books
⭐️ Presentations: Presentations by Teri Radichel
⭐️ Recognition: SANS Award, AWS Security Hero, IANS Faculty
⭐️ Certifications: SANS ~ GSE 240
⭐️ Education: BA Business, Master of Software Engineering, Master of Infosec
⭐️ Company: Penetration Tests, Assessments, Phone Consulting ~ 2nd Sight Lab
Need Help With Cybersecurity, Cloud, or Application Security?
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
🔒 Request a penetration test or security assessment
🔒 Schedule a consulting call
🔒 Cybersecurity Speaker for Presentation
Follow for more stories like this:
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 
❤️ Sign Up my Medium Email List
❤️ Twitter: @teriradichel
❤️ LinkedIn: https://www.linkedin.com/in/teriradichel
❤️ Mastodon: @teriradichel@infosec.exchange
❤️ Facebook: 2nd Sight Lab
❤️ YouTube: @2ndsightlab
S3
AWS
Bucket
Delete
MFA
Recommended from ReadMedium