<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Ayaan Bordoloi</title>
    <description>The latest articles on DEV Community by Ayaan Bordoloi (@ayaan49).</description>
    <link>https://dev.to/ayaan49</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F1085787%2Fa992e433-c204-406d-ade5-86a6ad3f7404.jpeg</url>
      <title>DEV Community: Ayaan Bordoloi</title>
      <link>https://dev.to/ayaan49</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/ayaan49"/>
    <language>en</language>
    <item>
      <title>Configuring OIDC and IRSA for Amazon EKS</title>
      <dc:creator>Ayaan Bordoloi</dc:creator>
      <pubDate>Thu, 15 Aug 2024 13:01:09 +0000</pubDate>
      <link>https://dev.to/ayaan49/configuring-oidc-and-irsa-for-amazon-eks-b8a</link>
      <guid>https://dev.to/ayaan49/configuring-oidc-and-irsa-for-amazon-eks-b8a</guid>
      <description>&lt;p&gt;&lt;em&gt;Learn how to configure OIDC provider with EKS and how to create IRSA. &lt;a href="https://github.com/Ayaan49/devops-qr-code/tree/main/opentofu" rel="noopener noreferrer"&gt;Source code is available in github&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Overview
&lt;/h2&gt;

&lt;p&gt;In this blog, you will learn how to configure &lt;strong&gt;EKS cluster&lt;/strong&gt;, &lt;strong&gt;OpenID connect (OIDC)&lt;/strong&gt;, &lt;strong&gt;IAM roles&lt;/strong&gt;, and &lt;strong&gt;Kubernetes Service accounts&lt;/strong&gt; using &lt;strong&gt;OpenTofu/Terraform&lt;/strong&gt;. I will mainly use this configuration for granting permissions to read, write and list objects in my &lt;strong&gt;S3 bucket&lt;/strong&gt;, but you can use this configuration to create your own IAM roles and policies for any Amazon service.&lt;br&gt;
&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fcz2cr05buzwr0q0v2ku7.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fcz2cr05buzwr0q0v2ku7.png" alt="Image description" width="800" height="571"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;We will basically follow these five steps to achieve this:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Create an IAM &lt;strong&gt;OpenID Connect(OIDC)&lt;/strong&gt; provider for your cluster.&lt;/li&gt;
&lt;li&gt;Create &lt;strong&gt;IAM policy&lt;/strong&gt; with permissions to write objects to your S3 bucket.&lt;/li&gt;
&lt;li&gt;Create &lt;strong&gt;IAM role&lt;/strong&gt; to access this policy.&lt;/li&gt;
&lt;li&gt;Attach the IAM role and policy.&lt;/li&gt;
&lt;li&gt;Use a &lt;strong&gt;Service Account&lt;/strong&gt; to securely grant your pods AWS access via an IAM role.&lt;/li&gt;
&lt;/ol&gt;
&lt;h2&gt;
  
  
  OIDC provider configuration
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;OpenID Connect (OIDC)&lt;/strong&gt; is used to securely connect your Kubernetes Service Account with an AWS IAM role. This allows your pods to assume the IAM role and access AWS services like S3 without needing AWS credentials directly inside the pods.&lt;/p&gt;

&lt;p&gt;I created this OIDC provider using OpenTofu configuration file for my EKS cluster:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;data "tls_certificate" "eks" {
  url = aws_eks_cluster.[your_cluster_name].identity[0].oidc[0].issuer
}

resource "aws_iam_openid_connect_provider" "eks" {
  client_id_list  = ["sts.amazonaws.com"]
  thumbprint_list = [data.tls_certificate.eks.certificates[0].sha1_fingerprint]
  url             = aws_eks_cluster.[your_cluster_name].identity[0].oidc[0].issuer
}

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;Replace &lt;code&gt;[your_cluster_name]&lt;/code&gt; with your actual cluster name.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Create IAM policy
&lt;/h2&gt;

&lt;p&gt;The IAM policy determines what your pods can do on AWS resources (e.g., access S3) when they assume the associated IAM role.&lt;/p&gt;

&lt;p&gt;I created the necessary IAM policy using OpenTofu to access my S3 bucket:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;resource "aws_iam_policy" "eks_s3_access_policy" {
  name        = "eks-s3-access-policy"
  policy      = &amp;lt;&amp;lt;EOF
{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Action": [
                "s3:ListBucket"
            ],
            "Resource": "arn:aws:s3:::[your_bucket_name]"
        },
        {
            "Effect": "Allow",
            "Action": [
                "s3:PutObject",
                "s3:GetObject"
            ],
            "Resource": "arn:aws:s3:::[your_bucket_name]/*"
        },
        {
            "Effect": "Allow",
            "Action": "s3:PutObjectAcl",
            "Resource": "arn:aws:s3:::[your_bucket_name]/*"
        }

            ]
}
EOF
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;Replace &lt;code&gt;[your_bucket_name]&lt;/code&gt; with your actual bucket name.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Create an IAM role
&lt;/h2&gt;

&lt;p&gt;The IAM role enables your &lt;strong&gt;Kubernetes&lt;/strong&gt; pods to securely access AWS services by assuming the role through the &lt;strong&gt;ServiceAccount&lt;/strong&gt;, inheriting the permissions specified in the attached &lt;strong&gt;IAM policy&lt;/strong&gt; which we created before this step.&lt;/p&gt;

&lt;p&gt;Creating an IAM role:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;resource "aws_iam_role" "eks_s3_access" {
  name = "eks-s3-access"

  assume_role_policy = &amp;lt;&amp;lt;EOF
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Principal": {
        "Federated": "${aws_iam_openid_connect_provider.eks.arn}"
      },
      "Action": "sts:AssumeRoleWithWebIdentity",
      "Condition": {
        "StringEquals": {
          "${replace(aws_iam_openid_connect_provider.eks.url, "https://", "")}:sub": "system:serviceaccount:default:s3-access-sa"
        }
      }
    }
  ]
}
EOF
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;AWS IAM supports federated identities using OIDC. This feature allows us to authenticate AWS API calls with supported identity providers and receive a valid OIDC JSON web token (JWT). We are passing this token to the AWS STS &lt;code&gt;AssumeRoleWithWebIdentity&lt;/code&gt; API operation and receive IAM temporary role credentials. Such credentials can be used to communicate with services likes Amazon S3 and DynamoDB.&lt;/p&gt;

&lt;h2&gt;
  
  
  Attach the policy to the IAM role
&lt;/h2&gt;

&lt;p&gt;I have created a OpenTofu configuration file to create this policy and role attachment for the ServiceAccount to use:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;resource "aws_iam_role_policy_attachment" "eks_s3_access_policy_attachment" {
  role       = aws_iam_role.eks_s3_access.name
  policy_arn = aws_iam_policy.eks_s3_access_policy.arn
}

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Finally, we will create a ServiceAccount in our cluster which serves as the Kubernetes identity that allows your pods to securely assume the AWS IAM role. This enables the pods to access AWS resources like S3 with the permissions defined in the IAM policy, without requiring AWS credentials to be manually managed or exposed within the cluster.&lt;/p&gt;

&lt;h2&gt;
  
  
  Create ServiceAccount
&lt;/h2&gt;

&lt;p&gt;The Service Account in this setup is crucial for securely allowing Kubernetes pods to assume an AWS IAM role, enabling them to access AWS resources, such as S3, without needing to embed AWS credentials directly in the pods.&lt;/p&gt;

&lt;p&gt;Here is &lt;strong&gt;YAML&lt;/strong&gt; file I used to create the &lt;code&gt;ServiceAccount&lt;/code&gt; in my cluster:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;apiVersion: v1
kind: ServiceAccount
metadata:
  name: s3-access-sa
  annotations:
    eks.amazonaws.com/role-arn: arn:aws:iam::[AWS account ID]:role/eks-s3-access

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Replace the &lt;code&gt;[AWS account ID]&lt;/code&gt; with your actual account ID.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;eks.amazonaws.com/role-arn: arn:aws:iam::[AWS account ID]:role/eks-s3-access&lt;/code&gt; is used to map your Kubernetes Service Account to the AWS IAM role. &lt;/p&gt;

&lt;p&gt;Now, you have got the necessary permissions to give access to a Workload running inside the cluster to resources outside of the cluster such as the S3 bucket.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;In this article, we explored how to securely grant a Kubernetes pod access to AWS resources using IAM roles. This approach is particularly useful for scenarios where workloads running inside the cluster need to interact with external AWS services.&lt;/p&gt;

&lt;p&gt;Based on my experience, getting it up and running wasn't a quick task. However, I hope this guide helps others save time and avoid the same challenges.&lt;/p&gt;

</description>
      <category>terraform</category>
      <category>eks</category>
      <category>s3</category>
      <category>aws</category>
    </item>
    <item>
      <title>Mastering Connectivity: CG-NAT Solutions with Tailscale</title>
      <dc:creator>Ayaan Bordoloi</dc:creator>
      <pubDate>Mon, 29 Jan 2024 14:01:15 +0000</pubDate>
      <link>https://dev.to/ayaan49/mastering-connectivity-cg-nat-solutions-with-tailscale-4a5d</link>
      <guid>https://dev.to/ayaan49/mastering-connectivity-cg-nat-solutions-with-tailscale-4a5d</guid>
      <description>&lt;p&gt;Recently, the CEO of Supabase tweeted about the importance of transitioning from &lt;code&gt;IPv4&lt;/code&gt; to &lt;code&gt;IPv6&lt;/code&gt;. This is due to the shortage of &lt;code&gt;IPv4&lt;/code&gt; addresses, and major cloud providers like AWS are set to start charging for &lt;code&gt;IPv4&lt;/code&gt; addresses starting from &lt;strong&gt;February 1, 2024&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F1bxh6fhw20qsx23ocm9f.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F1bxh6fhw20qsx23ocm9f.png" alt="Image description"&gt;&lt;/a&gt;&lt;br&gt;
Not everyone is fully ready to adopt &lt;code&gt;IPv6&lt;/code&gt; because of its complexities. To lawfully and technically circumvent these issues, I will demonstrate two methods in two clouds which I learned in &lt;a href="https://thecloudseminar.com/" rel="noopener noreferrer"&gt;The Cloud Seminar&lt;/a&gt; recently. These solutions don't always work, but in most cases, one can definitely bypass the restrictions.&lt;/p&gt;

&lt;p&gt;First, I will discuss what tailscale is and how we can use tailscale to translate a private &lt;code&gt;IPv4&lt;/code&gt; address to public &lt;code&gt;IPv4&lt;/code&gt; address using &lt;strong&gt;CGNAT&lt;/strong&gt; CIDR.&lt;/p&gt;

&lt;h2&gt;
  
  
  Tailscale
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Tailscale&lt;/strong&gt; is a &lt;em&gt;VPN&lt;/em&gt; service that enables encrypted point-to-point connections using the open source &lt;strong&gt;WireGuard&lt;/strong&gt; protocol, making devices and applications accessible anywhere in the world, securely and effortlessly. It offers speed, stability, and simplicity over traditional VPNs.&lt;/p&gt;

&lt;p&gt;We will use tailsacle to convert our private &lt;code&gt;IPV4&lt;/code&gt; address to public &lt;code&gt;IPV4&lt;/code&gt; address using &lt;strong&gt;CGNAT&lt;/strong&gt; CIDR. So, what &lt;strong&gt;CGNAT&lt;/strong&gt; does is it involves the translation of private IP addresses used within a local network into a smaller set of public IP addresses when the traffic passes through the ISP's network.&lt;/p&gt;

&lt;h2&gt;
  
  
  Cloud Machine Access via Console Connect
&lt;/h2&gt;

&lt;p&gt;Now, I will be working in the &lt;strong&gt;Hetzner&lt;/strong&gt; cloud to demonstrate how we can &lt;strong&gt;SSH&lt;/strong&gt; into our cloud machine without a public IP using tailscale.&lt;/p&gt;

&lt;h3&gt;
  
  
  Steps:
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Login to the console and create a project in the cloud.&lt;/li&gt;
&lt;li&gt;Start creating your server by adding the required machine details. ( I picked an ubuntu machine)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;While creating the server in my &lt;strong&gt;Hetzner&lt;/strong&gt; Cloud console, I unchecked the Public &lt;code&gt;IPv4&lt;/code&gt; option and only checked the public &lt;code&gt;IPv6&lt;/code&gt; option because it was charging me a certain amount of money to enable it.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fsknxfm8nssmbknt0azsk.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fsknxfm8nssmbknt0azsk.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Finally, create the server after filling in all the required details for the machine you need.&lt;/li&gt;
&lt;li&gt;After creating your server, your server dashboard will be visible. (I named my server tailscale-connect)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fj4o8j9j4iw4z4acyrdpv.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fj4o8j9j4iw4z4acyrdpv.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;At the top of your server dashboard you will see a console connect option, &lt;strong&gt;click&lt;/strong&gt; on that.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fcft6oeom3pg4w33kj3p4.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fcft6oeom3pg4w33kj3p4.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The instance connection will open and you will see the following screen:&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F0ue8i4qajex2x2ifgtp1.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F0ue8i4qajex2x2ifgtp1.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now, to log in to the server, it asks for a login username and login password, which we don't know. We will reset the login username and password to connect to the server.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Navigate to the rescue screen on your server dashboard and click &lt;code&gt;"Reset Root Password."&lt;/code&gt; (After clicking, you will receive a new root password. Save it somewhere.)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fswij4k94in94ei8mqkpo.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fswij4k94in94ei8mqkpo.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Now, refresh the page and open the console connect terminal again to login with the new root password. (Type your new root password which you generated in the previous step.)&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;You will see the following screen after successfully logging into your server- &lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F1szfv3xsycgfb9veogh5.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F1szfv3xsycgfb9veogh5.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;ul&gt;
&lt;li&gt;The top arrow indicates the private &lt;code&gt;IPv4&lt;/code&gt; address, and the arrow below indicates the &lt;code&gt;IPv6&lt;/code&gt; address that the cloud provided us.&lt;/li&gt;
&lt;li&gt;Since, we didn't enable the public &lt;code&gt;IPv4&lt;/code&gt; address(because of extra cost) we didn't get one.&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;

&lt;p&gt;Even though we connected to the instance through the console, we still haven't connected it through our machine, and it is not possible to do so without a public &lt;code&gt;IPv4&lt;/code&gt; address. To circumvent this issue, we will use &lt;strong&gt;tailscale&lt;/strong&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Tailscale installation
&lt;/h3&gt;

&lt;p&gt;Head to the terminal and install tailscale on your linux machine with the following command:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

curl -fsSL https://tailscale.com/install.sh | sh


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;ul&gt;
&lt;li&gt;Once your installation is complete, type &lt;code&gt;tailscale up&lt;/code&gt; and go to the link that tailscale provided in the terminal.&lt;/li&gt;
&lt;li&gt;You will see the following screen:&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fcr5qhvl3tf2wqgprg7m4.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fcr5qhvl3tf2wqgprg7m4.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Sign in&lt;/strong&gt; to tailscale using any of the provided methods.&lt;/li&gt;
&lt;li&gt;You will see the following screen after singing up-&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fqwbghgrjr7gfbmop3i78.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fqwbghgrjr7gfbmop3i78.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The tailscale dashboard displays all the devices connected to your network.(Currently it's only your local machine)&lt;/li&gt;
&lt;li&gt;Now, we will connect the cloud machine to the same network and then access it through our local machine without a public &lt;code&gt;IPv4&lt;/code&gt; address.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Let's see how to do that in the next steps.&lt;/p&gt;

&lt;h2&gt;
  
  
  Tailscale: SSH connect without Public IP
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Head to the cloud machine terminal that we logged into earlier.&lt;/li&gt;
&lt;li&gt;We will install tailscale on this machine and connect it to the network that we created previously.&lt;/li&gt;
&lt;li&gt;Type the following command to install tailscale on your cloud machine&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

curl -fsSL https://tailscale.com/install.sh | sh


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;ul&gt;
&lt;li&gt;Once your installation is complete, type &lt;code&gt;tailscale up&lt;/code&gt; and go to the link that tailscale provided in the terminal.&lt;/li&gt;
&lt;li&gt;On the sign-up page, sign in with the same account that you used to sign up on your local machine.( In my case, I used my &lt;strong&gt;github&lt;/strong&gt; account.)&lt;/li&gt;
&lt;li&gt;Once you have signed in, you will now see two machines on the dashboard: one being your local machine and the other being your cloud machine.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Frvxlnsc3wff1l5b2z9aj.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Frvxlnsc3wff1l5b2z9aj.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Now that we have connected the two machines on the same network, we can access the cloud machine through our local machine without requiring a public &lt;code&gt;IPv4&lt;/code&gt; address.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Copy the CGNAT IP of your cloud machine provided by Tailscale from your dashboard.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Open your terminal and type the following to connect to your cloud machine&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

ssh root@[CGNAT-IP]


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fffbkdjmo0tg0u00n67e3.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fffbkdjmo0tg0u00n67e3.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Now, you have successfully connected to your cloud machine through your local machine without requiring a public &lt;code&gt;IPv4&lt;/code&gt; address. How cool is that?!!&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F9sx4y2emuzq6y9xfw2rt.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F9sx4y2emuzq6y9xfw2rt.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;We don't need the console login terminal anymore, so we can close it and directly access the machine via our machine terminal.&lt;/p&gt;

&lt;h2&gt;
  
  
  EC2: SSH connect without public &lt;code&gt;IPv4&lt;/code&gt;
&lt;/h2&gt;

&lt;p&gt;Now, to implement the above method, we need to log in to the server using the cloud provider's console connect. Unfortunately, &lt;strong&gt;AWS&lt;/strong&gt; console connect doesn't support public &lt;code&gt;IPv6&lt;/code&gt; addresses, only &lt;code&gt;IPv4&lt;/code&gt;. AWS will charge $0.005 per IP per hour for public &lt;code&gt;IPv4&lt;/code&gt;, leading to high costs. To address this, create a Jump box (Bastion Host) in the public subnet using a public &lt;code&gt;IPv4&lt;/code&gt; address and connect other machines through it using private IPs. This reduces costs, as only one machine is billed for the public &lt;code&gt;IPv4&lt;/code&gt; address, with others connected via private IPs.&lt;/p&gt;

&lt;h3&gt;
  
  
  Steps:
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Log into your &lt;strong&gt;AWS&lt;/strong&gt; console.&lt;/li&gt;
&lt;li&gt;Head over to the &lt;em&gt;VPC&lt;/em&gt; section and create a &lt;em&gt;VPC&lt;/em&gt; for your instances.&lt;/li&gt;
&lt;li&gt;In the &lt;em&gt;VPC&lt;/em&gt; section, create two &lt;strong&gt;subnets&lt;/strong&gt; (Public &amp;amp; Private) allowing &lt;code&gt;IPv4&lt;/code&gt; &lt;strong&gt;CIDR&lt;/strong&gt; blocks for both and a &lt;code&gt;IPv6&lt;/code&gt; &lt;strong&gt;CIDR&lt;/strong&gt; block for private only.&lt;/li&gt;
&lt;li&gt;Create an Internet gateway (&lt;strong&gt;IGW&lt;/strong&gt;) and attach it to your VPC.&lt;/li&gt;
&lt;li&gt;Create a &lt;strong&gt;route table&lt;/strong&gt; and associate it with the public subnet. Edit the route and add a destination of &lt;code&gt;0.0.0.0&lt;/code&gt;, choosing the destination as the &lt;strong&gt;IGW&lt;/strong&gt; you created in the previous step.&lt;/li&gt;
&lt;li&gt;Similarly, create a Route table and associate it with the private subnet. No need to edit route here.&lt;/li&gt;
&lt;li&gt;Head over to &lt;strong&gt;EC2&lt;/strong&gt; instances and create a key pair first.&lt;/li&gt;
&lt;li&gt;Create an EC2 instance (&lt;strong&gt;JUMPBOX&lt;/strong&gt;) in the public subnet of your VPC, allowing the option for auto-assigning a &lt;code&gt;public IPv4&lt;/code&gt;. In the security group, allow SSH from my IP.&lt;/li&gt;
&lt;li&gt;Try to &lt;strong&gt;SSH&lt;/strong&gt; into it from your terminal and see if it's working.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fpmjag44g9jpil1tl28bd.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fpmjag44g9jpil1tl28bd.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Next, create one or two instances (test instances) in the private subnet of your &lt;em&gt;VPC&lt;/em&gt;. Disable the auto-assign public &lt;code&gt;IPv4&lt;/code&gt; address and enable the auto-assign &lt;code&gt;IPv6&lt;/code&gt; address.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fqlv3euxx15s0zre2wrk2.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fqlv3euxx15s0zre2wrk2.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;We cannot SSH into the Test instances because we have disabled the public &lt;code&gt;IPv4&lt;/code&gt; option. We only have a private &lt;code&gt;IPv4&lt;/code&gt; address and an &lt;code&gt;IPv6&lt;/code&gt; address. To SSH into the test instances, we will use the &lt;strong&gt;JUMPBOX&lt;/strong&gt;, which has an &lt;code&gt;IPv4&lt;/code&gt; address assigned to it.&lt;/li&gt;
&lt;li&gt;Head over to config file in the .ssh folder.&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

cd .ssh
code .


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;ul&gt;
&lt;li&gt;Paste the following in the config file&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;

Host JUMPBOX
  HostName &lt;span class="o"&gt;[&lt;/span&gt;Public IP of JUMPBOX]
  ForwardAgent &lt;span class="nb"&gt;yes
  &lt;/span&gt;StrictHostKeyChecking ask
  IdentityFile ~/.ssh/[private-key]
  User ubuntu

Host &lt;span class="o"&gt;[&lt;/span&gt;Private IP of &lt;span class="nb"&gt;test &lt;/span&gt;instance]
  ProxyCommand ssh &lt;span class="nt"&gt;-q&lt;/span&gt; &lt;span class="nt"&gt;-W&lt;/span&gt; %h:%p JUMPBOX
  ForwardAgent &lt;span class="nb"&gt;yes
  &lt;/span&gt;IdentityFile ~/.ssh/[private-key]
  User ubuntu

Host &lt;span class="o"&gt;[&lt;/span&gt;Private IP of 2nd &lt;span class="nb"&gt;test &lt;/span&gt;instance]
  ProxyCommand ssh &lt;span class="nt"&gt;-q&lt;/span&gt; &lt;span class="nt"&gt;-W&lt;/span&gt; %h:%p JUMPBOX
  ForwardAgent &lt;span class="nb"&gt;yes
  &lt;/span&gt;IdentityFile ~/.ssh/[private-key]
  User ubuntu


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;ul&gt;
&lt;li&gt;Please update the above file with the details of your own machine and then save and exit.&lt;/li&gt;
&lt;li&gt;Add the following rule in the security group of your test instances and then save it.(Custom IP is the CIDR of your VPC)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fe1idzs8k3verwtbqikdw.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fe1idzs8k3verwtbqikdw.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Now, head over to the terminal and ssh into your test instances through your &lt;strong&gt;private IP&lt;/strong&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fc5nvwy9baqmd4b9e4000.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fc5nvwy9baqmd4b9e4000.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;This is how we can &lt;strong&gt;SSH&lt;/strong&gt; into our instances without a public &lt;code&gt;IPv4&lt;/code&gt; address. This method can reduce the cost to a great extent. You can also install a &lt;strong&gt;NAT gateway&lt;/strong&gt; in your public subnet to access the internet on these machines.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;In this blog, I discussed how we can &lt;strong&gt;SSH&lt;/strong&gt; into our cloud machines from our local machine without the use of public &lt;code&gt;IPv4&lt;/code&gt; addresses, and with the help of Tailscale using the &lt;strong&gt;CGNAT&lt;/strong&gt; CIDR, thus saving the cost of using a public IPv4 address. I also discussed how we can create a &lt;strong&gt;JUMPBOX&lt;/strong&gt; to do the same but with the cost of paying for only one &lt;code&gt;IPv4&lt;/code&gt; network rather than paying for &lt;code&gt;IPv4&lt;/code&gt; addresses for all the machines. These are some great alternatives to save the extra cost without transitioning into &lt;code&gt;IPv6&lt;/code&gt; addresses.&lt;/p&gt;

</description>
      <category>cloudskills</category>
      <category>networking</category>
      <category>tutorial</category>
      <category>aws</category>
    </item>
    <item>
      <title>Kubernetes Cluster Setup Using Kubeadm on AWS</title>
      <dc:creator>Ayaan Bordoloi</dc:creator>
      <pubDate>Sun, 10 Dec 2023 14:50:04 +0000</pubDate>
      <link>https://dev.to/ayaan49/kubernetes-cluster-setup-using-kubeadm-on-aws-2096</link>
      <guid>https://dev.to/ayaan49/kubernetes-cluster-setup-using-kubeadm-on-aws-2096</guid>
      <description>&lt;p&gt;In this blog, I will explain how to setup a Kubernetes cluster with one &lt;code&gt;master node&lt;/code&gt; and two &lt;code&gt;worker nodes&lt;/code&gt; using Kubeadm. We will be doing it on the AWS cloud.&lt;/p&gt;

&lt;h2&gt;
  
  
  Prerequisites for this setup:
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://aws.amazon.com/" rel="noopener noreferrer"&gt;AWS&lt;/a&gt; account.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://mobaxterm.mobatek.net/download-home-%20%0Aedition.html" rel="noopener noreferrer"&gt;MobaXterm&lt;/a&gt; installed on your system. &lt;/li&gt;
&lt;li&gt;Knowledge about Kubernetes architecture. You can checkout this 
&lt;a href="https://youtu.be/BgrQ16r84pM?si=rj8o4yNs_xo2g4iW" rel="noopener noreferrer"&gt;video&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  What is Kubeadm?
&lt;/h2&gt;

&lt;p&gt;Kubeadm is a tool to setup kubernetes clusters without any complex configurations. It performs the actions necessary to get a minimum viable cluster up and running. It is developed and maintained by the official Kubernetes community. You can create a production-like cluster locally on a workstation for development and testing purposes with kubeadm.&lt;/p&gt;

&lt;h2&gt;
  
  
  Kubeadm prerequisites:
&lt;/h2&gt;

&lt;p&gt;We need to create the EC2 instances with the following configurations:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Launch one Ubuntu instance with minimum of &lt;code&gt;2 vCPU&lt;/code&gt; and &lt;code&gt;2GB RAM&lt;/code&gt; 
for the master node.&lt;/li&gt;
&lt;li&gt;Launch two Ubuntu instances with minimum of &lt;code&gt;1vCPU&lt;/code&gt; and &lt;code&gt;2 GB RAM&lt;/code&gt; 
for the worker nodes.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Kubeadm port requirements:
&lt;/h2&gt;

&lt;p&gt;Enable the following ports in the security groups of the instances:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Control plane node:
&lt;code&gt;
`6443/tcp` for Kubernetes API Server
`2379-2380` for etcd server client API
`10248-10260` for Kubelet API, Kube-scheduler, Kube-controller-manager, Read-Only Kubelet API, Kubelet health
`80,8080,443` Generic Ports
`30000-32767` for NodePort Services
&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Worker plane node:
&lt;code&gt;
`10248-10260` for Kubelet API etc
`30000-32767` for NodePort Services
&lt;/code&gt;
## Cluster setup steps:&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Here are the major steps involved in this setup:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Launch 3 EC2 t2.medium instances with the specified ports open.&lt;/li&gt;
&lt;li&gt;Install container runtime on all nodes. We will use &lt;a href="https://cri-o.io/" rel="noopener noreferrer"&gt;cri-o&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Install &lt;code&gt;Kubeadm&lt;/code&gt;, &lt;code&gt;Kubelet&lt;/code&gt;, and &lt;code&gt;kubectl&lt;/code&gt; on all the nodes.&lt;/li&gt;
&lt;li&gt;Initiate Kubeadm control plane configuration on the master 
node.&lt;/li&gt;
&lt;li&gt;Install the &lt;code&gt;Calico&lt;/code&gt; network plugin. &lt;/li&gt;
&lt;li&gt;Join the worker node to the master node using the join command.&lt;/li&gt;
&lt;li&gt;Validate all cluster components and nodes.&lt;/li&gt;
&lt;li&gt;Deploy a sample app and validate the app to test our cluster.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Let's start with the setup now!&lt;/p&gt;

&lt;h2&gt;
  
  
  Launch EC2 instances:
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Launch 3 &lt;code&gt;t2.medium&lt;/code&gt; instances and SSH into them through 
MobaXterm. &lt;/li&gt;
&lt;li&gt;Open the 3 nodes in the &lt;code&gt;multi-execution mode&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F4dy9cib1k3tzspfnjcqh.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F4dy9cib1k3tzspfnjcqh.png" alt="Image description"&gt;&lt;/a&gt; &lt;/p&gt;

&lt;p&gt;Refer to this &lt;a href="https://youtu.be/hUoYVZlioRc?si=qMJUQiUJrwMWHQqd" rel="noopener noreferrer"&gt;video&lt;/a&gt; if you're new to MobaXterm.&lt;/p&gt;

&lt;h2&gt;
  
  
  Run on all the nodes of the cluster as root user-
&lt;/h2&gt;

&lt;h3&gt;
  
  
  1. Disable SWAP
&lt;/h3&gt;

&lt;p&gt;We need to disable Swap for kubeadm to work properly.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;swapoff -a
sed -i '/ swap / s/^\(.*\)$/#\1/g' /etc/fstab
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;h3&gt;
  
  
  2. Enable iptables Bridged Traffic on all the Nodes
&lt;/h3&gt;

&lt;p&gt;Execute the following commands on all the nodes for IPtables to see bridged traffic. Here we are tweaking some kernel parameters and setting them using sysctl.&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;cat &amp;lt;&amp;lt;EOF | sudo tee /etc/modules-load.d/k8s.conf
overlay
br_netfilter
EOF

sudo modprobe overlay
sudo modprobe br_netfilter

# sysctl params required by setup, params persist across reboots
cat &amp;lt;&amp;lt;EOF | sudo tee /etc/sysctl.d/k8s.conf
net.bridge.bridge-nf-call-iptables  = 1
net.bridge.bridge-nf-call-ip6tables = 1
net.ipv4.ip_forward                 = 1
EOF

# Apply sysctl params without reboot
sudo sysctl --system
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;h3&gt;
  
  
  3. Install CRI-O Runtime
&lt;/h3&gt;

&lt;p&gt;The basic requirement for a Kubernetes cluster is a container runtime. We can use any container runtime we want, here we will be using CRI-O.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Enable cri-o repositories for version 1.28&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;OS="xUbuntu_22.04"

VERSION="1.28"

cat &amp;lt;&amp;lt;EOF | sudo tee /etc/apt/sources.list.d/devel:kubic:libcontainers:stable.list
deb https://download.opensuse.org/repositories/devel:/kubic:/libcontainers:/stable/$OS/ /
EOF
cat &amp;lt;&amp;lt;EOF | sudo tee /etc/apt/sources.list.d/devel:kubic:libcontainers:stable:cri-o:$VERSION.list
deb http://download.opensuse.org/repositories/devel:/kubic:/libcontainers:/stable:/cri-o:/$VERSION/$OS/ /
EOF
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;ul&gt;
&lt;li&gt;Add the GPG keys for CRI-O to the system’s list of trusted keys.&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;curl -L https://download.opensuse.org/repositories/devel:kubic:libcontainers:stable:cri-o:$VERSION/$OS/Release.key | sudo apt-key --keyring /etc/apt/trusted.gpg.d/libcontainers.gpg add -
curl -L https://download.opensuse.org/repositories/devel:/kubic:/libcontainers:/stable/$OS/Release.key | sudo apt-key --keyring /etc/apt/trusted.gpg.d/libcontainers.gpg add -
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;ul&gt;
&lt;li&gt;Update and install crio and crio-tools.&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;sudo apt-get update
sudo apt-get install cri-o cri-o-runc cri-tools -y
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;ul&gt;
&lt;li&gt;Reload the systemd configurations and enable cri-o.&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;sudo systemctl daemon-reload
sudo systemctl enable crio --now
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;The cri-tools include crictl, a CLI utility for interacting with containers created by the container runtime. When utilizing container runtimes other than Docker, you can employ the crictl utility for debugging containers on the nodes.&lt;/p&gt;

&lt;h3&gt;
  
  
  4. Install Kubeadm &amp;amp; Kubelet &amp;amp; Kubectl
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Install the required dependencies&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;sudo apt-get update
sudo apt-get install -y apt-transport-https ca-certificates curl
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;ul&gt;
&lt;li&gt;Download the GPG key&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;sudo curl -fsSLo /usr/share/keyrings/kubernetes-archive-keyring.gpg https://dl.k8s.io/apt/doc/apt-key.gpg
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;ul&gt;
&lt;li&gt;Add the Kubernetes APT repository to your system.&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;echo "deb [signed-by=/usr/share/keyrings/kubernetes-archive-keyring.gpg] https://apt.kubernetes.io/ kubernetes-xenial main" | sudo tee /etc/apt/sources.list.d/kubernetes.list
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;ul&gt;
&lt;li&gt;Update apt repo&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;sudo apt-get update -y
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;ul&gt;
&lt;li&gt;Install the latest version&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;sudo apt-get install -y kubelet kubeadm kubectl
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;ul&gt;
&lt;li&gt;Add hold to the packages to prevent upgrades.&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;sudo apt-mark hold kubelet kubeadm kubectl
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;ul&gt;
&lt;li&gt;Add the node IP to KUBELET_EXTRA_ARGS.&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;sudo apt-get install -y jq
local_ip="$(ip --json a s | jq -r '.[] | if .ifname == "eth1" then .addr_info[] | if .family == "inet" then .local else empty end else empty end')"
cat &amp;gt; /etc/default/kubelet &amp;lt;&amp;lt; EOF
KUBELET_EXTRA_ARGS=--node-ip=$local_ip
EOF
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;We now, have all the required utilities and tools for configuring Kubernetes components using kubeadm.&lt;/p&gt;

&lt;p&gt;Now, let's initialize Kubeadm On Master Node To Setup Control Plane.&lt;/p&gt;

&lt;h3&gt;
  
  
  5. Initialize Kubeadm On Master Node
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Execute the commands in this section only on the master node.&lt;/li&gt;
&lt;li&gt;Set the following environment variables.&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;IPADDR=$(curl ifconfig.me &amp;amp;&amp;amp; echo "")
NODENAME=$(hostname -s)
POD_CIDR="192.168.0.0/16"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;ul&gt;
&lt;li&gt;Initialize the master node control plane configurations using the kubeadm command.&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;sudo kubeadm init --control-plane-endpoint=$IPADDR  --apiserver-cert-extra-sans=$IPADDR  --pod-network-cidr=$POD_CIDR --node-name $NODENAME --ignore-preflight-errors Swap
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;You should get the following output:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fo0ivtprkghh8r36gf6no.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fo0ivtprkghh8r36gf6no.jpg" alt="Image description"&gt;&lt;/a&gt;&lt;br&gt;
Copy the join command save it somewhere, we will need it for joining the worker node to the master.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Use the following commands from the output to create the kubeconfig in master so that you can use kubectl to interact with cluster API.&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;mkdir -p $HOME/.kube
sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
sudo chown $(id -u):$(id -g) $HOME/.kube/config
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;ul&gt;
&lt;li&gt;Now, verify the kubeconfig by executing the following kubectl command to list all the pods in the kube-system namespace.&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;kubectl get po -n kube-system
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;You should get the following output:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fag3w6wd7a50j3iqd9pbb.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fag3w6wd7a50j3iqd9pbb.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;You verify all the cluster component health statuses using the following command.&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;kubectl get --raw='/readyz?verbose'
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;You should get the following output:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F2npktsyhk6bswy026osh.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F2npktsyhk6bswy026osh.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;By default, apps won’t get scheduled on the master node. If you want to use the master node for scheduling apps, taint the master node.&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;kubectl taint nodes --all node-role.kubernetes.io/control-plane-
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Next, we will be installing CNI tool for pod networking.&lt;/p&gt;

&lt;h3&gt;
  
  
  6. Install Calico Network Plugin
&lt;/h3&gt;

&lt;p&gt;Kubeadm does not configure any network plugin. You need to install a network plugin of your choice for kubernetes pod networking and enable network policy.&lt;/p&gt;

&lt;p&gt;We will use the Calico network plugin for this setup.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Run the following commands to install the Calcio network plugin&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;kubectl create -f https://raw.githubusercontent.com/projectcalico/calico/v3.26.1/manifests/tigera-operator.yaml

curl https://raw.githubusercontent.com/projectcalico/calico/v3.26.1/manifests/custom-resources.yaml -O

kubectl create -f custom-resources.yaml
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;h3&gt;
  
  
  7. Joining of Worker nodes to master node
&lt;/h3&gt;

&lt;p&gt;Now, let’s join the worker node to the master node using the Kubeadm join command you have got in the output while setting up the master node.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Execute the commands in this section only on the worker 
nodes.&lt;/li&gt;
&lt;li&gt;Here is what the command looks like in my case&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;kubeadm join 3.86.197.238:6443 --token 3nf11u.w40mnymbrlkr8f88 \
        --discovery-token-ca-cert-hash sha256:d904af14e6bee5af2020e2b1a9572345403b1a1c7a095bb5e8584e04f1db3667
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;You should get the following output:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Feev6c2ixgvia0aakytxd.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Feev6c2ixgvia0aakytxd.jpg" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Execute the kubectl command from the master node to check if the node is added to the master.&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;kubectl get nodes
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;You will get the following output:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fomdtlgw5a2ay8o9ugpgf.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fomdtlgw5a2ay8o9ugpgf.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You can further add more nodes with the same join command.&lt;/p&gt;

&lt;h3&gt;
  
  
  8. Deploy a sample Nginx App
&lt;/h3&gt;

&lt;p&gt;Create an Nginx deployment. Execute the following directly on the command line.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;kubectl run nginx --image=nginx --port=80 
kubectl expose pod nginx --port=80 --type=NodePort
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;A random port between &lt;code&gt;30000-32767&lt;/code&gt; and assigned to nginx app.&lt;br&gt;
To access that port we run the following command:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;kubectl get svc
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;You get an output like this:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fq6l9olzxhqaowdl0ejw3.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fq6l9olzxhqaowdl0ejw3.jpg" alt="Image description"&gt;&lt;/a&gt;&lt;br&gt;
Here, we can see that the nginx app has been deployed on the port 30501.&lt;/p&gt;

&lt;p&gt;We can now access that port with our master node ip or worker nodes ip and get the following result:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F7g8q228nhq7211qiz9fp.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F7g8q228nhq7211qiz9fp.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This shows that we have setup our cluster succesfully!&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;In this blog, I have explained how to deploy our own Kubernetes cluster using Kubeadm on AWS. This setup is good for learning and playing around with kubernetes.&lt;/p&gt;

&lt;p&gt;Thanks for reading!&lt;/p&gt;

</description>
      <category>kubernetes</category>
      <category>kubeadm</category>
      <category>aws</category>
      <category>devops</category>
    </item>
  </channel>
</rss>
