<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0" xmlns:media="http://search.yahoo.com/mrss/"><channel><title><![CDATA[Prabhat Agarwal - Whackd]]></title><description><![CDATA[Thoughts, research and ideas.]]></description><link>https://whackd.in/</link><image><url>https://whackd.in/favicon.png</url><title>Prabhat Agarwal - Whackd</title><link>https://whackd.in/</link></image><generator>Ghost 5.68</generator><lastBuildDate>Tue, 31 Mar 2026 14:50:50 GMT</lastBuildDate><atom:link href="https://whackd.in/author/prabhat/rss/" rel="self" type="application/rss+xml"/><ttl>60</ttl><item><title><![CDATA[Accessing S3 content using CloudFront Signed URL]]></title><description><![CDATA[<p>In this post, we will configure AWS CloudFront distribution to provide restricted access to S3 bucket private contents so that objects can only be accessed through CloudFront Signed URL.</p><p>A signed URL includes additional information such as expiration date, that provide user applications to have better control over access to</p>]]></description><link>https://whackd.in/accessing-s3-content-using-cloudfront-signed-url/</link><guid isPermaLink="false">630876e77e780403f24812c2</guid><category><![CDATA[AWS]]></category><category><![CDATA[S3]]></category><category><![CDATA[CloudFront]]></category><category><![CDATA[Cloud]]></category><dc:creator><![CDATA[Prabhat Agarwal]]></dc:creator><pubDate>Fri, 26 Aug 2022 11:08:40 GMT</pubDate><media:content url="https://whackd.in/content/images/2023/09/Untitled-design.png" medium="image"/><content:encoded><![CDATA[<img src="https://whackd.in/content/images/2023/09/Untitled-design.png" alt="Accessing S3 content using CloudFront Signed URL"><p>In this post, we will configure AWS CloudFront distribution to provide restricted access to S3 bucket private contents so that objects can only be accessed through CloudFront Signed URL.</p><p>A signed URL includes additional information such as expiration date, that provide user applications to have better control over access to the content.</p><h3 id="prerequisite">Prerequisite</h3><ol><li>AWS account with console access.</li><li>Any Java IDE to generate signed URL code</li><li>OpenSSL utility to generate public/Private Key</li></ol><p>Now let&#x2019;s start with the steps for the workflow.</p><h3 id="create-s3-bucket">Create S3 Bucket</h3><p>Login to AWS console search for S3 service or go to https://s3.console.aws.amazon.com</p><figure class="kg-card kg-image-card"><img src="https://whackd.in/content/images/2022/08/S3-console.png" class="kg-image" alt="Accessing S3 content using CloudFront Signed URL" loading="lazy" width="752" height="236" srcset="https://whackd.in/content/images/size/w600/2022/08/S3-console.png 600w, https://whackd.in/content/images/2022/08/S3-console.png 752w" sizes="(min-width: 720px) 720px"></figure><p>Click on S3 that leads to S3 console and follow the <strong>Create bucket</strong> button that lands to create bucket form.</p><figure class="kg-card kg-image-card"><img src="https://whackd.in/content/images/2022/08/s3_console_2.png" class="kg-image" alt="Accessing S3 content using CloudFront Signed URL" loading="lazy" width="602" height="238" srcset="https://whackd.in/content/images/size/w600/2022/08/s3_console_2.png 600w, https://whackd.in/content/images/2022/08/s3_console_2.png 602w"></figure><p>Choose a globally unique and valid name for the bucket, choose AWS region for which logged in user have persimmon to create bucket. Make sure the &#x201C;<strong>Block <em>all</em> public access</strong>&#x201D; checkbox is checked. Left rest of the settings to default and click on create bucket.</p><h3 id="create-a-key-pair">Create a key pair</h3><p>In following steps, OpenSSL is used to create key pair to make a trusted key pair group for CloudFront.</p><p>There are other tools as well to create public/private key pairs.</p><ul><li>Use the following command to generate RSA key pair and save it in a file named <strong>private_key.pem</strong>.</li></ul><pre><code>openssl genrsa -out private_key.pem 2048</code></pre><ul><li>The following command will extract the public key from the generated file and save it in <strong>public_key.pem</strong>.</li></ul><pre><code>openssl rsa -pubout -in private_key.pem -out public_key.pem</code></pre><ul><li>Later this post will use java to generate signed URLs so the private key pair file cannot be used directly, instead PEM to DER conversion is required. Use the following command to do so.</li></ul><pre><code>openssl pkcs8 -topk8 -nocrypt -in private_key.pem -inform PEM -out private_key.der -outform DER</code></pre><p>Keep aside the files created as these will be required later while creating CloudFront Distribution to be used as signers to create signed URLs.</p><h3 id="creating-the-signers-in-cloudfront">Creating the signers in CloudFront</h3><p>Use the following steps to create a signer in cloud front,</p><ul><li>Open CloudFront Console and from the left hamburger menu, navigate to public keys under key management section.</li></ul><figure class="kg-card kg-image-card"><img src="https://whackd.in/content/images/2022/08/key_management-83.png" class="kg-image" alt="Accessing S3 content using CloudFront Signed URL" loading="lazy" width="329" height="117"></figure><ul><li>Go to Public keys and create one by providing appropriate name and paste the contents of <strong><em>public_key.pem</em> </strong>file in Key section.</li><li>In the same key management section, go to key groups and create a key group with the public key created in previous step.</li></ul><p>Now let&#x2019;s move on and create cloud front distribution.</p><h3 id="create-cloudfront-distribution">Create CloudFront Distribution</h3><p>Search for CloudFront in AWS console.</p><figure class="kg-card kg-image-card"><img src="https://whackd.in/content/images/2022/08/cloud_front_console.png" class="kg-image" alt="Accessing S3 content using CloudFront Signed URL" loading="lazy" width="752" height="213" srcset="https://whackd.in/content/images/size/w600/2022/08/cloud_front_console.png 600w, https://whackd.in/content/images/2022/08/cloud_front_console.png 752w" sizes="(min-width: 720px) 720px"></figure><p>Open CloudFront console and click on &#x201C;<strong>Create a CloudFront distribution</strong>&#x201D; that opens the create CloudFront distribution form.</p><figure class="kg-card kg-image-card"><img src="https://whackd.in/content/images/2022/08/cloud_front_form_1.png" class="kg-image" alt="Accessing S3 content using CloudFront Signed URL" loading="lazy" width="602" height="166" srcset="https://whackd.in/content/images/size/w600/2022/08/cloud_front_form_1.png 600w, https://whackd.in/content/images/2022/08/cloud_front_form_1.png 602w"></figure><p>From the origin dropdown, select the bucket created in previous step as Origin domain.</p><figure class="kg-card kg-image-card"><img src="https://whackd.in/content/images/2022/08/cloud_front_form_2.png" class="kg-image" alt="Accessing S3 content using CloudFront Signed URL" loading="lazy" width="602" height="306" srcset="https://whackd.in/content/images/size/w600/2022/08/cloud_front_form_2.png 600w, https://whackd.in/content/images/2022/08/cloud_front_form_2.png 602w"></figure><p>For <strong><em>Origin access</em></strong>, choose from options given,</p><p><strong>1. Origin access control settings</strong>, which is recommended where you need to update the bucket policy, to allow access to IAM service principal, provided when distribution is created, <strong><em>or</em></strong></p><p><strong>2. Legacy access identities</strong> where an option to update the bucket policy is provided. This will update the S3 bucket policy so that the bucket can be accessible using the cloud front distribution.</p><p>Choose the recommended one and create control setting and use the same.</p><figure class="kg-card kg-image-card"><img src="https://whackd.in/content/images/2022/08/cloud_front_form_3.png" class="kg-image" alt="Accessing S3 content using CloudFront Signed URL" loading="lazy" width="602" height="331" srcset="https://whackd.in/content/images/size/w600/2022/08/cloud_front_form_3.png 600w, https://whackd.in/content/images/2022/08/cloud_front_form_3.png 602w"></figure><p>Choose <strong><em>Allowed HTTP methods</em></strong>as required.</p><figure class="kg-card kg-image-card"><img src="https://whackd.in/content/images/2022/08/cloud_front_form_4.png" class="kg-image" alt="Accessing S3 content using CloudFront Signed URL" loading="lazy" width="602" height="201" srcset="https://whackd.in/content/images/size/w600/2022/08/cloud_front_form_4.png 600w, https://whackd.in/content/images/2022/08/cloud_front_form_4.png 602w"></figure><p>In Restrict viewer access, select yes and keep Trusted authorization type as Trusted key groups. In Add key groups section, select the key group from the drop down created in previously.</p><figure class="kg-card kg-image-card"><img src="https://whackd.in/content/images/2022/08/cloud_front_form_5.png" class="kg-image" alt="Accessing S3 content using CloudFront Signed URL" loading="lazy" width="602" height="256" srcset="https://whackd.in/content/images/size/w600/2022/08/cloud_front_form_5.png 600w, https://whackd.in/content/images/2022/08/cloud_front_form_5.png 602w"></figure><p>This will bind the key pair created in previous section so that one must need to create CloudFront Signed URL to access S3 Bucket content associated with distribution.</p><p>In cache and Origin Request, select <strong><em>CachingDisabled</em></strong> so that any update in s3 object will immediately reflected while fetching it.</p><figure class="kg-card kg-image-card"><img src="https://whackd.in/content/images/2022/08/cloud_front_form_.6.png" class="kg-image" alt="Accessing S3 content using CloudFront Signed URL" loading="lazy" width="602" height="209" srcset="https://whackd.in/content/images/size/w600/2022/08/cloud_front_form_.6.png 600w, https://whackd.in/content/images/2022/08/cloud_front_form_.6.png 602w"></figure><p>Now create CloudFront distribution keeping other options as default.</p><p>On success distribution detail page will open where on top of the page, copy the policy statement.</p><figure class="kg-card kg-image-card"><img src="https://whackd.in/content/images/2022/08/cloud_front_success.png" class="kg-image" alt="Accessing S3 content using CloudFront Signed URL" loading="lazy" width="602" height="132" srcset="https://whackd.in/content/images/size/w600/2022/08/cloud_front_success.png 600w, https://whackd.in/content/images/2022/08/cloud_front_success.png 602w"></figure><h3 id="update-access-policy-in-s3-bucket">Update access policy in S3 bucket</h3><p>Go to S3 console (https://s3.console.aws.amazon.com) and select the same bucket used in cloud front distribution as origin.</p><p>Move to bucket policy section under Permission tab, edit the bucket policy and paste the contents of bucket policy copied.</p><figure class="kg-card kg-image-card"><img src="https://whackd.in/content/images/2022/08/bucket_policy_1-1.png" class="kg-image" alt="Accessing S3 content using CloudFront Signed URL" loading="lazy" width="602" height="432" srcset="https://whackd.in/content/images/size/w600/2022/08/bucket_policy_1-1.png 600w, https://whackd.in/content/images/2022/08/bucket_policy_1-1.png 602w"></figure><p>For this policy, the allowed action is restricted to read the objects, that can be modified as per requirement. Let&#x2019;s update the action and add permission to write objects as well. To do so, replace the action line with following.</p><blockquote>&quot;Action&quot;: [&quot;s3:GetObject&quot;,&quot;s3:PutObject&quot;],</blockquote><p>The resulting statement will look like mentioned below.</p><figure class="kg-card kg-image-card"><img src="https://whackd.in/content/images/2022/08/bucket_policy_2.png" class="kg-image" alt="Accessing S3 content using CloudFront Signed URL" loading="lazy" width="602" height="334" srcset="https://whackd.in/content/images/size/w600/2022/08/bucket_policy_2.png 600w, https://whackd.in/content/images/2022/08/bucket_policy_2.png 602w"></figure><p>Save the changes.</p><p>With this configuration part is completed and now let&#x2019;s move on to create cloud front signed URL.</p><h3 id="generating-cloudfront-signed-url">Generating CloudFront Signed URL</h3><p>Steps and code to generate cloud front signed URL is explained below.</p><p>Create spring boot gradle project and add the below dependencies to it.</p><blockquote>implementation &apos;com.amazonaws:aws-java-sdk-cloudfront:1.12.283&apos;</blockquote><p>Here is the code for generating cloud front signed URL.</p><pre><code class="language-java">import java.io.File;
import java.io.IOException;
import java.security.spec.InvalidKeySpecException;
import java.util.Date;

import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

import com.amazonaws.services.cloudfront.CloudFrontUrlSigner;
import com.amazonaws.services.cloudfront.util.SignerUtils;

@SpringBootApplication
public class CloudfrontsignedurlApplication implements CommandLineRunner {

	public static void main(String[] args) {
		SpringApplication.run(CloudfrontsignedurlApplication.class, args);
	}

	@Override
	public void run(String... args) throws Exception {
		String cloudFrontKeyPairId = &quot;&lt;public_key_id&gt;&quot;; // public key id created in cloud front key management section.
		String distributionDomain = &quot;&lt;cloud_front_distribution_name&gt;&quot;; // cloud front distribution domain name.
		String key = &quot;cloudfrontsignedurl/objetc1.txt&quot;; // S3 bucket object path

		Date expirationDate = new Date(System.currentTimeMillis() + 7200000); // Token will be valid for 2 hour
		try {
			File cloudFrontPrivateKeyFile = generateCloudFrontPrivateKeyFile();
			String signedUrl = CloudFrontUrlSigner.getSignedURLWithCannedPolicy(SignerUtils.Protocol.https,
					distributionDomain, cloudFrontPrivateKeyFile, key, cloudFrontKeyPairId, expirationDate);
			System.out.println(signedUrl);

		} catch (IOException | InvalidKeySpecException exception) {
			throw new Exception(exception.getMessage());
		}
	}

	private File generateCloudFrontPrivateKeyFile() {
		File file = new File(&quot;&lt;private_key_file&gt;&quot;); // Path to public/private key pair file.
		return file;
	}
}
</code></pre><p>The generated signed URL will look as mentioned below.</p><blockquote><a href="#">https://d26doxj2i1y97q.cloudfront.net/cloudfrontsignedurl/objetc1.txt?Expires=1661499384&amp;Signature=LabCbO27wL1-ErAEwYU9CBGh1pVdmRY2oQ94QfQP9cGi4vQTNgo7xT3ctbr6lAolcH5AZEe-I79s~spEA6VCnRUIstsvDhLoN4spJHrQxlecapxKK7P0J9U6kXL8V2ucDgwrJmFfdFWpipeGkgTVgKJ~s53Unp76YrTJODYnX-ZZc3RuQ4go5oBYhXU2hRHKlVusV3llhlOyfN58FxytzAZkegECRj6LR6m0WzRI-guCPqHCO7Gir~Ls5ewCw-TZpAyMca-LjKAeTGd~KS4etFgr5Tbt3UrGiDXJVoDkCcc-Z1cu9xu34s9ZQHqSD-t7AHdCszv6sitRcFK9PSJQyg__&amp;Key-Pair-Id=K1HEUAHR3KG1E3</a></blockquote><p>This URL can be used to upload and download the object to S3 bucket.</p><p>Note** One also need to set the <strong>Access Key ID</strong> and <strong>Secret Access Key </strong>for programmatic access.</p><!--kg-card-begin: markdown--><p>Complete code for generating the signed URL can be found at <a href="https://github.com/aprabhat/cloudfrontsignedurl?ref=whackd.in" target="_blank">Github</a>.</p>
<!--kg-card-end: markdown-->]]></content:encoded></item><item><title><![CDATA[Automate Kubernetes deployment using Argo CD]]></title><description><![CDATA[<p>Argo CD is a declarative Git-Ops continuous delivery tool created for Kubernetes.</p><p><strong>k8s</strong> application manifests should be version controlled in a git repository. <strong><a href="https://argoproj.github.io/argo-cd/?ref=whackd.in">Argo CD </a></strong>uses the git repository as a source of truth which represent the desired state of the application.</p><p><strong>Argo CD</strong> is implemented as a <strong>k8s</strong> controller</p>]]></description><link>https://whackd.in/automate-k8s-deployment-using-argocd/</link><guid isPermaLink="false">624866e20c979a0e7a1019d3</guid><category><![CDATA[Devops]]></category><category><![CDATA[Kubernetes]]></category><category><![CDATA[k8s]]></category><category><![CDATA[ArgoCD]]></category><category><![CDATA[CICD]]></category><category><![CDATA[automation]]></category><dc:creator><![CDATA[Prabhat Agarwal]]></dc:creator><pubDate>Tue, 21 Sep 2021 15:53:34 GMT</pubDate><media:content url="https://whackd.in/content/images/2021/09/image-14.png" medium="image"/><content:encoded><![CDATA[<img src="https://whackd.in/content/images/2021/09/image-14.png" alt="Automate Kubernetes deployment using Argo CD"><p>Argo CD is a declarative Git-Ops continuous delivery tool created for Kubernetes.</p><p><strong>k8s</strong> application manifests should be version controlled in a git repository. <strong><a href="https://argoproj.github.io/argo-cd/?ref=whackd.in">Argo CD </a></strong>uses the git repository as a source of truth which represent the desired state of the application.</p><p><strong>Argo CD</strong> is implemented as a <strong>k8s</strong> controller which continuously monitor current or live state with the desired state described in the git repository and automate the deployment of desired state in <strong>k8s</strong> environment.</p><h3 id="prerequisite">Prerequisite</h3><p>Before moving forward, some tools are required to complete the exercise,</p><ul><li>A local Kubernetes cluster, for example <a href="https://www.docker.com/products/docker-desktop?ref=whackd.in">Docker Desktop</a> or <a href="https://minikube.sigs.k8s.io/docs/start/?ref=whackd.in">Minikube</a></li><li><a href="https://kubernetes.io/docs/tasks/tools/?ref=whackd.in#kubectl">kubectl</a></li><li>Git account and git CLI</li><li>Argo CD</li></ul><p>The installation instructions for local Kubernetes cluster can be found in respective links.</p><h3 id="installing-argo-cd">Installing Argo CD</h3><p>As mentioned before, <strong>Argo CD</strong> is implemented as a custom controller, so it needs to be deployed in <strong>k8s</strong>.</p><p>Let&apos;s create a separate namespace for <strong>Argo CD</strong> installation.</p><pre><code class="language-shell">kubectl create ns argocd</code></pre><!--kg-card-begin: html--><div class="protip">
    <h5 class><span>
            <svg xmlns="http://www.w3.org/2000/svg" class="icon icon-tabler icon-tabler-bulb" width="44" height="44" viewbox="0 0 24 24" stroke-width="1.5" stroke="#2c3e50" fill="none" stroke-linecap="round" stroke-linejoin="round" style="
    width: 30px;
    fill: #ffec00;
">
                <path stroke="none" d="M0 0h24v24H0z" fill="none"/>
                <path d="M3 12h1m8 -9v1m8 8h1m-15.4 -6.4l.7 .7m12.1 -.7l-.7 .7"/>
                <path d="M9 16a5 5 0 1 1 6 0a3.5 3.5 0 0 0 -1 3a2 2 0 0 1 -4 0a3.5 3.5 0 0 0 -1 -3"/>
                <line x1="9.7" y1="17" x2="14.3" y2="17"/>
            </svg>
        </span>
        Protip
    </h5>
    <p>To switch into a namespace, if you want to work within it for long, you can use:
        <code>kubectl config set-context --current --namespace=argocd</code>
    </p>
    <p>This official way is a little complex to remember and run every time when you want to switch to a new namespace.
        To get rid of this, you can grab a tool called <code>kubens</code> which is in kubectx package for mac and
        Linux, since I am using windows, I need to install it separately using,
        <code>choco install kubens --version=0.9.1</code>
    </p>
    <p>After installing kubens, you can list down all namespaces in current context using kubens and to print out the
        current namespace you can use <code>kubens -c</code></p>
    <p>To switch to argocd namespace, we can now use
        <code>kubens argocd</code> which is much easier to remember and handy.
    </p>
</div><!--kg-card-end: html--><p>Coming back to our main section, now lets install <strong>ArgoCD</strong> in newly created namespace.</p><pre><code class="language-shell">kubectl apply -n argocd -f https://raw.githubusercontent.com/argoproj/argo-cd/stable/manifests/install.yaml</code></pre><p>This took around <em>3-5 minutes</em>, you can check the status of deployment using <code>kubectl get deployment</code> which will give output as follows:</p><pre><code class="language-shell">NAME                 READY   UP-TO-DATE   AVAILABLE   AGE
argocd-dex-server    1/1     1            1           5m28s
argocd-redis         1/1     1            1           5m28s
argocd-repo-server   1/1     1            1           5m28s
argocd-server        1/1     1            1           5m28s</code></pre><h3 id="access-argo-cd-api-server">Access Argo CD API Server</h3><p>By default, the Argo CD API server is not exposed with an external IP. To access the API server, choose one of the following techniques to expose the <strong>Argo CD API</strong> server:</p><!--kg-card-begin: markdown--><ol>
<li><code>kubectl patch svc argocd-server -n argocd -p &apos;{&quot;spec&quot;: {&quot;type&quot;: &quot;LoadBalancer&quot;}}&apos;</code></li>
<li><code>kubectl port-forward svc/argocd-server -n argocd 8081:443</code></li>
</ol>
<!--kg-card-end: markdown--><p>Use <code>localhost:8081</code> to access the API server in browser.</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://whackd.in/content/images/2021/09/image-4.png" class="kg-image" alt="Automate Kubernetes deployment using Argo CD" loading="lazy" width="1918" height="903" srcset="https://whackd.in/content/images/size/w600/2021/09/image-4.png 600w, https://whackd.in/content/images/size/w1000/2021/09/image-4.png 1000w, https://whackd.in/content/images/size/w1600/2021/09/image-4.png 1600w, https://whackd.in/content/images/2021/09/image-4.png 1918w" sizes="(min-width: 720px) 720px"><figcaption>ArgoCD Login Page</figcaption></figure><h3 id="login-to-argo-cd">Login to Argo CD</h3><p>Default username to login to Argo CD server is <code>admin</code>, to get the password there are several ways.</p><p><strong>One</strong> way is to get the initial admin password using command below. The password is <code>base 64</code> encoded, so if on windows use Git Bash to use the decode function.</p><pre><code class="language-shell">kubectl -n argocd get secret argocd-initial-admin-secret -o jsonpath=&quot;{.data.password}&quot; | base64 -d</code></pre><p>This will return the decoded password that can be used directly.</p><p><strong>Another</strong> way is to patch the <code>argocd-secret</code> and update the <code>admin.password</code> field which should be encrypted with Bcrypt password hashing function. One can use the online tools like <a href="https://bcrypt-generator.com/?ref=whackd.in"><strong>bcrypt-generator.com</strong></a> to get the hash.</p><p>Here the updated password is <code>admin</code>.</p><pre><code>kubectl -n argocd patch secret argocd-secret -p &apos;{&quot;stringData&quot;: {&quot;admin.password&quot;: &quot;$2a$10$aDulNEmKSuPr8rUH7CvMguvkz/x5wRJuiZgXOw4cc4Zzk2RhpRpBi&quot;, &quot;admin.passwordMtime&quot;: &quot;&apos;$(date +%FT%T)&apos;&quot;}}&apos;</code></pre><p>After login, target page will show the list of application. As there are no applications, so this section is blank for now.</p><figure class="kg-card kg-image-card"><img src="https://whackd.in/content/images/2021/09/image-5.png" class="kg-image" alt="Automate Kubernetes deployment using Argo CD" loading="lazy" width="1920" height="903" srcset="https://whackd.in/content/images/size/w600/2021/09/image-5.png 600w, https://whackd.in/content/images/size/w1000/2021/09/image-5.png 1000w, https://whackd.in/content/images/size/w1600/2021/09/image-5.png 1600w, https://whackd.in/content/images/2021/09/image-5.png 1920w" sizes="(min-width: 720px) 720px"></figure><h3 id="login-using-argo-cd-cli">Login using Argo CD CLI</h3><p>First install <strong>Argo CD CLI</strong> as per the operating system.</p><p>For mac or Linux, use the below command to install it.</p><pre><code class="language-shell">brew install argocd</code></pre><p>For windows, follow the <a href="https://github.com/argoproj/argo-cd/releases/tag/v2.1.2?ref=whackd.in"><strong>link</strong></a>, download and add the entry in path variable.</p><p>To login through <strong>CLI</strong>, use the command mentioned below:</p><pre><code class="language-shell">argocd login localhost:8081 --username admin --password admin --insecure</code></pre><p>Argo CD installation and Login part is completed. Now the next step is to create a demo application and update k8s manifest to deploy in cluster.</p><h3 id="the-demo-application">The Demo Application</h3><p>As it already discussed that <strong>Argo CD</strong> uses git repository to automate the deployment, so a git repository is required. Here I am using github repository.</p><pre><code class="language-shell">git clone https://github.com/aprabhat/argo-cd-color-app.git</code></pre><p>After cloning, switch to <code>dev</code> branch, check for the deploy folder and take a look at deployment and service manifest files.</p><p>Now create another namespace in which the demo application will be deployed.</p><pre><code class="language-shell">kubectl create ns practice</code></pre><p>Create <strong>k8s</strong> resource of type <strong>Argo CD</strong> application using the above repo as source. For this create <em>color-app.yaml</em> file with following content. Here, <code>targetRevision</code> represents the branch name and <code>path</code> represents the location from root directory where the <strong>k8s</strong> manifest resides.</p><pre><code class="language-yaml">apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
  name: color-app
  namespace: argocd
spec:
  project: default
  source:
    repoURL: https://github.com/aprabhat/argo-cd-color-app.git
    targetRevision: dev
    path: deploy
  destination:
    server: https://kubernetes.default.svc
    namespace: practice</code></pre><p>Save and apply this yaml file.</p><pre><code>kubectl apply -f app.yaml</code></pre><p>This will create a resource of type application. The new application is now available in <strong>Argo CD</strong> dashboard.</p><figure class="kg-card kg-image-card"><img src="https://whackd.in/content/images/2021/09/image-8.png" class="kg-image" alt="Automate Kubernetes deployment using Argo CD" loading="lazy" width="1920" height="904" srcset="https://whackd.in/content/images/size/w600/2021/09/image-8.png 600w, https://whackd.in/content/images/size/w1000/2021/09/image-8.png 1000w, https://whackd.in/content/images/size/w1600/2021/09/image-8.png 1600w, https://whackd.in/content/images/2021/09/image-8.png 1920w" sizes="(min-width: 720px) 720px"></figure><p>The app list and status can also be fetched by using Argo CD CLI using <code>argocd app list</code> command.</p><figure class="kg-card kg-image-card"><img src="https://whackd.in/content/images/2021/09/image-9.png" class="kg-image" alt="Automate Kubernetes deployment using Argo CD" loading="lazy" width="1898" height="82" srcset="https://whackd.in/content/images/size/w600/2021/09/image-9.png 600w, https://whackd.in/content/images/size/w1000/2021/09/image-9.png 1000w, https://whackd.in/content/images/size/w1600/2021/09/image-9.png 1600w, https://whackd.in/content/images/2021/09/image-9.png 1898w" sizes="(min-width: 720px) 720px"></figure><p>Click on the app tile in UI and check for the resources created for the application.</p><figure class="kg-card kg-image-card"><img src="https://whackd.in/content/images/2021/09/image-10.png" class="kg-image" alt="Automate Kubernetes deployment using Argo CD" loading="lazy" width="1920" height="904" srcset="https://whackd.in/content/images/size/w600/2021/09/image-10.png 600w, https://whackd.in/content/images/size/w1000/2021/09/image-10.png 1000w, https://whackd.in/content/images/size/w1600/2021/09/image-10.png 1600w, https://whackd.in/content/images/2021/09/image-10.png 1920w" sizes="(min-width: 720px) 720px"></figure><p>The app is created but not deployed as the <code>syncPolicy</code> is not set and default to manual. So a manual synchronization is required.</p><pre><code>argocd app sync color-app</code></pre><p>Once the sync is completed, the application details UI will also be updated with all the resources created for k8s application.</p><figure class="kg-card kg-image-card"><img src="https://whackd.in/content/images/2021/09/image-11.png" class="kg-image" alt="Automate Kubernetes deployment using Argo CD" loading="lazy" width="1578" height="640" srcset="https://whackd.in/content/images/size/w600/2021/09/image-11.png 600w, https://whackd.in/content/images/size/w1000/2021/09/image-11.png 1000w, https://whackd.in/content/images/2021/09/image-11.png 1578w" sizes="(min-width: 720px) 720px"></figure><p>Now let&apos;s update the application to be on auto sync mode. To do so, update the color-app.yaml file for <code>syncPolicy</code> and apply it again using <code>kubectl apply -f color-app.yaml</code>.</p><pre><code class="language-yaml">apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
  name: color-app
  namespace: argocd
spec:
  project: default
  source:
    repoURL: https://github.com/aprabhat/argo-cd-color-app.git
    targetRevision: dev
    path: deploy
  destination:
    server: https://kubernetes.default.svc
    namespace: practice
  syncPolicy:
    automated: {}</code></pre><p>To test the auto sync, update the <a href="https://github.com/aprabhat/argo-cd-color-app/blob/dev/deploy/color-deployment.yaml?ref=whackd.in">deployment.yaml</a> file for replicas and push the change to git repository. Check the application details in <strong>Argo CD UI</strong> dashboard for the pods if they scaled to 2.</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://whackd.in/content/images/2021/09/image-12.png" class="kg-image" alt="Automate Kubernetes deployment using Argo CD" loading="lazy" width="1580" height="634" srcset="https://whackd.in/content/images/size/w600/2021/09/image-12.png 600w, https://whackd.in/content/images/size/w1000/2021/09/image-12.png 1000w, https://whackd.in/content/images/2021/09/image-12.png 1580w" sizes="(min-width: 720px) 720px"><figcaption>Argo CD Dashboard</figcaption></figure><p>This time as <code>syncPolicy</code> is set to automated, there is no need to do a manual sync.</p><p>Finally you can check for the deployed application. First describe the service from practice namespace using <code>kubectl -n practice describe svc color-service</code></p><pre><code>Name:                     color-service
Namespace:                practice
Labels:                   app.kubernetes.io/instance=color-app
Annotations:              &lt;none&gt;
Selector:                 app=color
Type:                     NodePort
IP Family Policy:         SingleStack
IP Families:              IPv4
IP:                       10.110.20.25
IPs:                      10.110.20.25
LoadBalancer Ingress:     localhost
Port:                     &lt;unset&gt;  3000/TCP
TargetPort:               3000/TCP
NodePort:                 &lt;unset&gt;  30007/TCP
Endpoints:                10.1.0.19:3000,10.1.0.20:3000
Session Affinity:         None
External Traffic Policy:  Cluster
Events:                   &lt;none&gt;</code></pre><p>To access the sample application deployed use the localhost:&lt;NodePort&gt;. In this case it is localhost:30007, open this in the browser. The nice UI will appear on the browser window.</p><figure class="kg-card kg-image-card"><img src="https://whackd.in/content/images/2021/09/image-16.png" class="kg-image" alt="Automate Kubernetes deployment using Argo CD" loading="lazy" width="1920" height="1030" srcset="https://whackd.in/content/images/size/w600/2021/09/image-16.png 600w, https://whackd.in/content/images/size/w1000/2021/09/image-16.png 1000w, https://whackd.in/content/images/size/w1600/2021/09/image-16.png 1600w, https://whackd.in/content/images/2021/09/image-16.png 1920w" sizes="(min-width: 720px) 720px"></figure><p>In few simple steps, you are able to automate the deployment of k8s application using Argo CD. </p><p>Although this post is not covering all the scenarios or production system use cases but it is a good place to have a glimpse of how Argo CD works and to understand how to automate k8s application deployment with Argo CD.</p><h3 id="conclusion">Conclusion</h3><p>In the era of microservice, as the number of <strong>k8s</strong> workloads keeps on increasing, deploying the tens or hundred of <em>pods</em> at the same time is a tedious task.</p><p>In this situation, <strong>Argo CD</strong> is a great tool which enable teams &#xA0;to automate the deployment on multiple environments(testing, staging production). <strong>Argo CD</strong> will definitely helps the scrum teams to save time by automating the Continuous Delivery process and reduce common errors.</p>]]></content:encoded></item><item><title><![CDATA[Demystifying JSON Web Token (JWT) Part-1]]></title><description><![CDATA[<p>JSON Web Token or <strong>JWT</strong> or sometimes pronounced as &apos;jot&apos; is an open standard (<a href="https://tools.ietf.org/html/rfc7519?ref=whackd.in">RFC-7519</a>) for transferring claims in a compact, printable and secure manner along with a signature that provide its authenticity between two parties as a JSON object. </p><p>JWTs can be signed using JSON Web Signature</p>]]></description><link>https://whackd.in/demystifying-jwts/</link><guid isPermaLink="false">624866e20c979a0e7a1019c9</guid><category><![CDATA[programming]]></category><category><![CDATA[Authorization]]></category><category><![CDATA[java]]></category><dc:creator><![CDATA[Prabhat Agarwal]]></dc:creator><pubDate>Mon, 23 Aug 2021 04:42:55 GMT</pubDate><media:content url="https://whackd.in/content/images/2023/09/jwt_img.png" medium="image"/><content:encoded><![CDATA[<img src="https://whackd.in/content/images/2023/09/jwt_img.png" alt="Demystifying JSON Web Token (JWT) Part-1"><p>JSON Web Token or <strong>JWT</strong> or sometimes pronounced as &apos;jot&apos; is an open standard (<a href="https://tools.ietf.org/html/rfc7519?ref=whackd.in">RFC-7519</a>) for transferring claims in a compact, printable and secure manner along with a signature that provide its authenticity between two parties as a JSON object. </p><p>JWTs can be signed using JSON Web Signature (<a href="https://tools.ietf.org/html/rfc7515?ref=whackd.in">RFC-7515</a>) and/or encrypted using JSON Web Encryption (<a href="https://tools.ietf.org/html/rfc7516?ref=whackd.in">RFC-7516</a>) and that provides a powerful and secured solution for transferring information in many different situations.</p><p>In this section we will focus on unencrypted JWTs, and will take the encrypted one in next part.</p><h2 id="structure-of-jwt">Structure of JWT</h2><p>JWT&apos;s contains 3 different components separated by dots(.)</p><ul><li>Header</li><li>Payload</li><li>Signature/Encryption Data</li></ul><p>The header and payload are mandatory and have certain structure(JSON). The third part(not a JSON object itself) which is signature depends upon the algorithm used for signing and can be omitted in case of unsecured/unencrypted JWTs.</p><p>JWT usage URL safe base64 encoding where &apos;+&apos; and &apos;/&apos; are substituted by &apos;-&apos; and &#xA0; &apos;_&apos; characters respectively. The resulting sequence is a string with format <code>header.payload.signature</code> and look like the following,</p><blockquote>eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c</blockquote><p>In this example, the base64url decoded header is</p><pre><code>{
  &quot;alg&quot;: &quot;HS256&quot;,
  &quot;typ&quot;: &quot;JWT&quot;
}</code></pre><p>the decoded payload is</p><pre><code>{
  &quot;sub&quot;: &quot;1234567890&quot;,
  &quot;name&quot;: &quot;John Doe&quot;,
  &quot;iat&quot;: 1516239022
}</code></pre><p>and the last part is the secret required to verify the signature.</p><p>Now lets see the details of mandatory part of JWT which is the <em>header</em> and the <em>payload.</em></p><h2 id="header">Header</h2><p>Also known as JOSE(<strong>J</strong>SON <strong>O</strong>bject <strong>S</strong>igning and <strong>E</strong>ncryption) Header is the first part of JWT token. There can be several fields in the header depends upon the type of JWT, for example, the only mandatory field for the unencrypted JWT is <em>alg </em>with value as none. For a signed JWTs, some fields can be <em>alg, jku, kid, typ.</em></p><p>The header part is a JSON object and has the following format</p><pre><code>{
  &quot;alg&quot;: &quot;RS256&quot;, // none in case of unencrypted jwt
  &quot;jku&quot;: &quot;url to the public key set&quot;,
  &quot;kid&quot;: &quot;key-id-1&quot;, //optional
  &quot;typ&quot;: &quot;JWT&quot;
}</code></pre><p>It is possible to add additional user defined claims to the header.</p><h2 id="payload">Payload</h2><p>Just like the header, payload is a JSON object. This is the part where all the user related data is added. It can contain claims with specific meaning known as <em>registered</em> <em>claim</em> along with some personal user data, although no claim is mandatory.</p><p>There are several reserved claims as per JWT specification that are non mandatory but seven claims are recommended to have for better interoperability. The seven claims are as follows,</p><ul><li><strong>iss</strong> (issuer): party that issued the JWT</li><li><strong>sub</strong> (subject): Identifies the user</li><li><strong>aud</strong> (audience): Recipients of JWT or the application that reading the data from JWT</li><li><strong>exp</strong> (expiration time): Time (seconds since epoch) after which the JWT expires</li><li><strong>nbf</strong> (not before time): Time (seconds since epoch) from which JWT is considered as valid.</li><li><strong>iat</strong> (issued at time): Time at which the JWT was issued</li><li><strong>jti</strong> (JWT ID): Unique identifier; can be used to differentiate JWT from similar content.</li></ul><p>You can see the complete list of reserved claims <a href="https://www.iana.org/assignments/jwt/jwt.xhtml?ref=whackd.in#claims">here</a>.</p><h2 id="unencrypted-jwts">Unencrypted JWTs</h2><p>So far we have learned about the header and the payload part which is enough to construct a unencrypted JWT token.</p><p>Unencrypted JWTs formed with simple header</p><pre><code>{
  &quot;alg&quot;: &quot;none&quot;,
  &quot;typ&quot;: &quot;JWT&quot;
}</code></pre><p>and with payload</p><pre><code>{
  &quot;sub&quot;: &quot;user108&quot;,
  &quot;name&quot;: &quot;Shakal&quot;,
  &quot;iat&quot;: 1629690269
}</code></pre><p>now lets create a unencrypted JWT using these two parts. The pseudo code for this would be as follows,</p><pre><code>token = base64urlEncode(header) + &quot;.&quot; + base64urlEncode(payload) + &quot;.&quot;</code></pre><p>You can use any coding language to write encode and decode functions. Here I am using java 8 Base64 encoding that is part of JDK</p><pre><code class="language-Java">import java.nio.charset.StandardCharsets;
import java.util.Base64;
public String base64urlEncode(String raw) {
    return Base64.getUrlEncoder().withoutPadding().encodeToString(raw.getBytes(StandardCharsets.UTF_8));
}</code></pre><p>We also need to remove the trailing equal signs (=), for this we are using the withoutPadding<code>()</code> function. The resulting string will look like</p><blockquote>ewogICJhbGciOiAibm9uZSIsCiAgInR5cCI6ICJKV1QiCn0<strong>.</strong>ewogICJzdWIiOiAidXNlcjEwOCIsCiAgIm5hbWUiOiAiU2hha2FsIiwKICAiaWF0IjogMTYyOTY5MDI2OQp9<strong>.</strong></blockquote><h2 id="conclusion">Conclusion</h2><p>Now we have the basic understanding of structure of JWTs and different parts used to create JWTs. We discussed about the first two parts of JWT which is the <em>header</em> and the <em>payload</em> and created a unsecured JWT. <br>I real world scenarios, the use of unsecured JWTs is very rare or not at all.</p><p>In the next part, we will discuss about encrypted or secured JWTs and have more details on signature part.</p>]]></content:encoded></item></channel></rss>