<?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:cc="http://cyber.law.harvard.edu/rss/creativeCommonsRssModule.html">
    <channel>
        <title><![CDATA[Stories by Andrzej Komarnicki on Medium]]></title>
        <description><![CDATA[Stories by Andrzej Komarnicki on Medium]]></description>
        <link>https://medium.com/@andrzejkomarnicki?source=rss-4297e3e49338------2</link>
        <image>
            <url>https://cdn-images-1.medium.com/fit/c/150/150/1*9ynH3v_f9pLftiTlIJAhBw.jpeg</url>
            <title>Stories by Andrzej Komarnicki on Medium</title>
            <link>https://medium.com/@andrzejkomarnicki?source=rss-4297e3e49338------2</link>
        </image>
        <generator>Medium</generator>
        <lastBuildDate>Sat, 14 Nov 2026 05:56:24 GMT</lastBuildDate>
        <atom:link href="https://medium.com/@andrzejkomarnicki/feed" rel="self" type="application/rss+xml"/>
        <webMaster><![CDATA[yourfriends@medium.com]]></webMaster>
        <atom:link href="http://medium.superfeedr.com/" rel="hub"/>
        <item>
            <title><![CDATA[Generate a custom type-safe Helm Chart construct with cdk8s]]></title>
            <link>https://medium.com/@andrzejkomarnicki/generate-a-custom-type-safe-helm-chart-construct-with-cdk8s-88dd27f486c0?source=rss-4297e3e49338------2</link>
            <guid isPermaLink="false">https://medium.com/p/88dd27f486c0</guid>
            <category><![CDATA[cdk8s]]></category>
            <category><![CDATA[kubernetes]]></category>
            <category><![CDATA[cdk]]></category>
            <category><![CDATA[typescript]]></category>
            <category><![CDATA[helm]]></category>
            <dc:creator><![CDATA[Andrzej Komarnicki]]></dc:creator>
            <pubDate>Mon, 01 Jul 2024 16:04:40 GMT</pubDate>
            <atom:updated>2024-07-01T16:04:40.127Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*-qv4TXjqgMxpru2DdYtEgQ.png" /></figure><p>Cloud Development Kit for Kubernetes (<strong>cdk8s</strong>) is a software development framework for defining Kubernetes applications and reusable abstractions using familiar programming languages and rich object-oriented APIs. cdk8s generates pure Kubernetes YAML — you can use cdk8s to define applications for any Kubernetes cluster running anywhere.</p><p>Recently the cdk8s team has expanded the capabilities of the “cdk8s import” command, simplifying the process to incorporate Helm charts. Providing a Helm Chart URL to the “cdk8s import” command will auto-generate a custom type-safe construct for you that represents the Helm Chart in question.</p><p>Let’s start by initializing a new cdk8s project in an empty directory:</p><pre>mkdir cdk8simporthelm &amp;&amp; cd cdk8simporthelm<br>cdk8s init typescript-app</pre><p>You should see the following basic structure of a cdk8s application with the <em>_constructs_</em> and <em>_cdk8s_</em> libraries:</p><pre>import { Construct } from &#39;constructs&#39;;<br>import { App, Chart, ChartProps } from &#39;cdk8s&#39;;<br>import { Redis, RedisArchitecture } from &#39;./imports/redis&#39;;<br><br>export class MyChart extends Chart {<br>  constructor(scope: Construct, id: string, props: ChartProps = {}) {<br>    super(scope, id, props);<br>    // define resources here<br>  }<br>}<br><br>const app = new App();<br>new MyChart(app, &#39;cdk8simporthelm&#39;);<br>app.synth();</pre><p>Now let’s go ahead and import the Bitnami Redis chart:</p><pre>cdk8s import helm:https://charts.bitnami.com/bitnami/redis@18.2.0</pre><p>Moving back to our <strong>main.ts</strong> file we can now import the new Redis module that was generated in the previous step:</p><pre>import { Construct } from &#39;constructs&#39;;<br>import { App, Chart, ChartProps } from &#39;cdk8s&#39;;<br>import { Redis, RedisArchitecture } from &#39;./imports/redis&#39;;<br><br>export class MyChart extends Chart {<br>  constructor(scope: Construct, id: string, props: ChartProps = {}) {<br>    super(scope, id, props);<br><br>    new Redis(this, &#39;Redis&#39;, {<br>      values: {<br>        architecture: RedisArchitecture.REPLICATION,     // &lt;------- type safe property<br>      }<br>    });<br>  }<br>}<br><br>const app = new App();<br>new MyChart(app, &#39;cdk8simporthelm&#39;);<br>app.synth();</pre><p>After we’re done adding anything else we need in addition to what’s above, let’s synthesize the k8s YAML manifest:</p><pre>cdk8s synth</pre><p>You should now have your manifest generated in the <strong>dist</strong> subfolder and you can run kubectl apply as you would with any other manifest.</p><p>You can find the source code repo for this blog post here: <a href="https://github.com/smallfriesdigital/cdk8s-helm-import">https://github.com/smallfriesdigital/cdk8s-helm-import</a></p><p>To access more info about Values Schema, Additional Values, Globals and Dependencies visit <a href="https://cdk8s.io/docs/latest/cli/import/#helm-charts">https://cdk8s.io/docs/latest/cli/import/#helm-charts</a></p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=88dd27f486c0" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Nested API routes with Node.js AWS Lambda Function URL, Middy HTTP router and AWS CDK]]></title>
            <link>https://medium.com/@andrzejkomarnicki/nested-api-routes-with-node-js-aws-lambda-function-url-middy-http-router-and-aws-cdk-734a33f24a9b?source=rss-4297e3e49338------2</link>
            <guid isPermaLink="false">https://medium.com/p/734a33f24a9b</guid>
            <category><![CDATA[aws-cdk]]></category>
            <category><![CDATA[nodejs]]></category>
            <category><![CDATA[aws-lambda]]></category>
            <category><![CDATA[aws]]></category>
            <category><![CDATA[serverless]]></category>
            <dc:creator><![CDATA[Andrzej Komarnicki]]></dc:creator>
            <pubDate>Thu, 25 Jan 2024 18:16:03 GMT</pubDate>
            <atom:updated>2024-01-25T18:16:03.699Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*Cpkmsn9ACb57ZfxL" /></figure><p>With the rising popularity of Function URLs, which are dedicated HTTP(S) endpoints for your Lambda function, we can avoid many of the complexities, costs and limitations associated with Amazon API Gateway. The downside is we also lose some of the nice features of an API Gateway that we get out of the box, one key feature being API routing based on method and path of an http event. This is where Middy, a Node.js middleware engine for AWS Lambda really comes in handy.</p><p>In particular, we can achieve nested http routing within our Lambdas by leveraging Middy’s <a href="https://middy.js.org/docs/routers/http-router">http-router</a> handler. Let’s start by cloning the starter project repo:</p><pre>git clone https://github.com/AndrzejKomarnicki/awscdk-nodejsfunction-middy</pre><p>Next let’s install the npm packages and run some AWS CDK CLI commands from the root working directory of our cloned repo.</p><pre>npm install<br>cdk synth &amp;&amp; cdk diff</pre><p>By default AWS CDK CLI will check your environment variables for your AWS creds and region first, if not found it will default back to your AWS credentials and config files. You can of course also specify the AWS CLI profile of choice. For more info on how to setup environments for your Stack instance head over to <a href="https://docs.aws.amazon.com/cdk/v2/guide/environments.html">https://docs.aws.amazon.com/cdk/v2/guide/environments.html</a>.</p><p>Anyway, if everything checks out let’s proceed to deploy the Stack as part of our CDK app:</p><pre>cdk deploy</pre><p>After deployment, you should see output similar to below:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*cg9E1_t2jj_bgMzt.png" /></figure><p>Next let’s dive into the Lambda function source code before we test the endpoints…</p><p>Open up <strong>index.ts</strong> from <em>/services/node-lambda/</em></p><pre>import middy from &quot;@middy/core&quot;;<br>import jsonBodyParser from &quot;@middy/http-json-body-parser&quot;;<br>import httpErrorHandler from &quot;@middy/http-error-handler&quot;;<br>import httpSecurityHeaders from &quot;@middy/http-security-headers&quot;;<br>import httpRouterHandler from &quot;@middy/http-router&quot;;<br>import { APIGatewayProxyEventV2, APIGatewayProxyResultV2 } from &quot;aws-lambda&quot;;<br>import { Logger, injectLambdaContext } from &quot;@aws-lambda-powertools/logger&quot;;<br><br>const logger = new Logger({<br>  logLevel: &quot;INFO&quot;,<br>  serviceName: &quot;middy-example-api&quot;,<br>});<br><br>async function getHandler(<br>  event: APIGatewayProxyEventV2,<br>  context: any<br>): Promise&lt;APIGatewayProxyResultV2&gt; {<br>  // the returned response will be checked against the type `APIGatewayProxyResultV2`<br>  logger.info(&quot;This is a INFO log with some context&quot;);<br>  console.log(&quot;event 👉&quot;, event);<br>  return {<br>    statusCode: 200,<br>    body: JSON.stringify(`Hello from ${event.rawPath}`),<br>  };<br>}<br><br>async function postHandler(<br>  event: APIGatewayProxyEventV2,<br>  context: any<br>): Promise&lt;APIGatewayProxyResultV2&gt; {<br>  // the returned response will be checked against the type `APIGatewayProxyResultV2`<br>  logger.info(&quot;This is a INFO log with some context&quot;);<br>  console.log(&quot;event 👉&quot;, event);<br>  return {<br>    statusCode: 200,<br>    body: JSON.stringify(event.body),<br>  };<br>}<br><br>// routes served by httpRouterHandler middleware<br>// you can add more nested handlers for routes (method and path) as needed<br>const routes = [<br>  {<br>    method: &quot;GET&quot;,<br>    path: &quot;/user/{id}&quot;,<br>    handler: getHandler,<br>  },<br>  {<br>    method: &quot;POST&quot;,<br>    path: &quot;/user&quot;,<br>    handler: postHandler,<br>  },<br>];<br><br>export const handler = middy()<br>  .use(jsonBodyParser())<br>  .use(httpSecurityHeaders())<br>  .use(httpErrorHandler())<br>  .use(injectLambdaContext(logger)) // Change to (logger, { logEvent: true }) to log the incoming event<br>  .handler(httpRouterHandler(routes));</pre><p>As you can tell we import <strong>httpRouterHandler</strong> from <em>@middy/http-router</em>, and we define two async node.js functions — <em>getHandler()</em> and <em>postHandler()</em>, which are referenced by the routes object as part of its handler property depending on http path and method in the http event.</p><p>Of course you can re-organize these nested Lambda handlers to be exported as modules instead of having everything in one monolithic index.ts file, this only serves as a starting point for demonstration purposes.</p><p>Let’s proceed to test our endpoints with the different paths and methods we defined. You can go back to the outputs generated by “CDK deploy” and test against both the <em>Function URL</em> and <em>CloudFront URL</em>.</p><pre>GET method on /user/{userid}</pre><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*_FAW9v4I4iSJQXpF.png" /></figure><pre>POST method on /user</pre><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*raktGT_O-ej2D_rA.png" /></figure><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=734a33f24a9b" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Deploy a MongoDB Atlas cluster on GCP with CDKTF using TypeScript]]></title>
            <link>https://medium.com/@andrzejkomarnicki/deploy-a-mongodb-atlas-cluster-on-gcp-with-cdktf-using-typescript-87adbf0252f4?source=rss-4297e3e49338------2</link>
            <guid isPermaLink="false">https://medium.com/p/87adbf0252f4</guid>
            <category><![CDATA[google-cloud-platform]]></category>
            <category><![CDATA[cdktf]]></category>
            <category><![CDATA[mongodb]]></category>
            <category><![CDATA[typescript]]></category>
            <category><![CDATA[terraform]]></category>
            <dc:creator><![CDATA[Andrzej Komarnicki]]></dc:creator>
            <pubDate>Fri, 19 Jan 2024 18:22:59 GMT</pubDate>
            <atom:updated>2024-01-19T18:22:59.095Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*DWI7fTnVH34qrgYiG4j_Kg.png" /></figure><p>HashiCorp announced the general availability of Terraform CDK back in August 2022, and since then we’ve seen the arrival of several enhancements and new pre-built providers-many available through the <a href="https://constructs.dev/">Construct Hub</a>. The beauty of CDKTF is that you can generate the code bindings for virtually any existing Terraform provider by simply using the cdktf cli and you can use the existing Terraform registry to look up a provider’s resource and argument reference.</p><p>The source code for this series can be found here: <a href="https://github.com/smallfriesdigital/cdktf-mongodbatlas-gcp">https://github.com/smallfriesdigital/cdktf-mongodbatlas-gcp</a>.</p><p>Let’s dive head first into initializng a new cdktf project within our working dir that uses the GCP provider:</p><pre>cdktf init --template=typescript --local --providers=&quot;google@~&gt;4.0&quot;</pre><p>Next let’s add the pre-built MongoDB Atlas provider:</p><pre>cdktf provider add mongodb/mongodbatlas</pre><p>OK, so now let’s update <em>MyStack</em> in main.ts with the following CDKTF TypeScript code:</p><pre>import { Construct } from &quot;constructs&quot;;<br>import { App, TerraformStack, TerraformVariable } from &quot;cdktf&quot;;<br>import { MongodbatlasProvider } from &quot;@cdktf/provider-mongodbatlas/lib/provider&quot;;<br>import { Project } from &quot;@cdktf/provider-mongodbatlas/lib/project&quot;;<br>import { Cluster } from &quot;@cdktf/provider-mongodbatlas/lib/cluster&quot;;<br><br>class MyStack extends TerraformStack {<br>  constructor(scope: Construct, id: string) {<br>    super(scope, id);<br><br>    // define secure environment variables (won&#39;t end up in cdk.tf.json)<br>    const publicKey = new TerraformVariable(this, &quot;publicKey&quot;, {<br>      type: &quot;string&quot;,<br>      description: &quot;MongoDB Atlas Org Public Key&quot;,<br>      sensitive: true,<br>    });<br><br>    const privateKey = new TerraformVariable(this, &quot;privateKey&quot;, {<br>      type: &quot;string&quot;,<br>      description: &quot;MongoDB Atlas Org Private Key&quot;,<br>      sensitive: true,<br>    });<br><br>    const orgId = new TerraformVariable(this, &quot;orgId&quot;, {<br>      type: &quot;string&quot;,<br>      description: &quot;MongoDB Atlas Org ID&quot;,<br>      sensitive: true,<br>    });<br><br>    // satisfy all the Atlas requirements before instantiating new cluster<br>    new MongodbatlasProvider(this, &quot;Atlas&quot;, {<br>      publicKey: publicKey.value, // secret set via environment variable TF_VAR_publicKey<br>      privateKey: privateKey.value, // secret set via environment variable TF_VAR_privateKey<br>    });<br><br>    const atlasProject = new Project(this, &quot;newProject&quot;, {<br>      name: &quot;CDKTFProject1&quot;,<br>      orgId: orgId.value, // set via environment variable TF_VAR_orgId<br>    });<br><br>    // create cluster resource<br>    new Cluster(this, &quot;newCluster1&quot;, {<br>      projectId: atlasProject.id,<br>      name: &quot;atlasClusterCDK&quot;,<br>      clusterType: &quot;REPLICASET&quot;,<br>      cloudBackup: false,<br>      mongoDbMajorVersion: &quot;5.0&quot;,<br>      providerName: &quot;TENANT&quot;,<br>      backingProviderName: &quot;GCP&quot;,<br>      providerInstanceSizeName: &quot;M0&quot;,<br>      providerRegionName: &quot;CENTRAL_US&quot;,<br><br>      replicationSpecs: [<br>        {<br>          numShards: 1,<br>          regionsConfig: [<br>            {<br>              electableNodes: 3,<br>              priority: 7,<br>              readOnlyNodes: 0,<br>              regionName: &quot;CENTRAL_US&quot;,<br>            },<br>          ],<br>        },<br>      ],<br>    });<br>  }<br>}<br><br>const app = new App();<br>new MyStack(app, &quot;cdktf-gcp-mongodbatlas&quot;);<br>app.synth();</pre><p>In this case we&#39;re using the free tier <em>M0 Sandbox</em> cluster, which is only recommended for development or testing purposes and doesn&#39;t support backups. Also keep in mind we are referencing the <em>Atlas Region</em> associated with the respective <em>Google Cloud Region</em>, not the GCP region name directly.<br>You can read more about that here: (<a href="https://www.mongodb.com/docs/atlas/reference/google-gcp/#std-label-google-gcp">https://www.mongodb.com/docs/atlas/reference/google-gcp/#std-label-google-gcp</a>)</p><blockquote>CDKTF Best Practices for handling secrets: use the TerraformVariable construct, Terraform uses the values in TerraformVariable directly at execution time, so CDKTF does not write them to the synthesized cdktf.json file. To pass a Terraform variable through environment variables, name the environment variable TF_VAR_NAME - &#39;NAME&#39; being a placeholder for your variable name.</blockquote><p>Environment variables that need to be set in the execution environment:</p><ul><li>TF_VAR_publicKey</li><li>TF_VAR_privateKey</li><li>TF_VAR_orgId</li></ul><p>You can now feel free to run cdktf plan and cdktf deploy in order to get the base setup going, or instead choose to do it at the end once we wrap up all the other resource additions.</p><p>Let&#39;s go back and update the existing Cluster resource by assigning it to a constant in main.ts, then adding the admin database user to that cluster.</p><pre>// create cluster resource<br>const atlasCluster = new Cluster(this, &quot;newCluster1&quot;, {<br>  projectId: atlasProject.id,<br>  name: &quot;atlasClusterCDK&quot;,<br>  clusterType: &quot;REPLICASET&quot;,<br>  cloudBackup: false,<br>  mongoDbMajorVersion: &quot;5.0&quot;,<br>  providerName: &quot;TENANT&quot;,<br>  backingProviderName: &quot;GCP&quot;,<br>  providerInstanceSizeName: &quot;M0&quot;,<br>  providerRegionName: &quot;CENTRAL_US&quot;,<br><br>  replicationSpecs: [<br>    {<br>      numShards: 1,<br>      regionsConfig: [<br>        {<br>          electableNodes: 3,<br>          priority: 7,<br>          readOnlyNodes: 0,<br>          regionName: &quot;CENTRAL_US&quot;,<br>        },<br>      ],<br>    },<br>  ],<br>});<br><br>const adminPassword = new TerraformVariable(this, &quot;adminPassword&quot;, {<br>  type: &quot;string&quot;,<br>  description: &quot;MongoDB Atlas Cluster DB Admin&quot;,<br>  sensitive: true,<br>});<br><br>// add admin user to cluster<br>new DatabaseUser(this, &quot;adminUser&quot;, {<br>  username: &quot;cdktf-adminuser&quot;,<br>  password: adminPassword.value, // secret set via environment variable TF_VAR_adminPassword<br>  projectId: atlasProject.id,<br>  authDatabaseName: &quot;admin&quot;,<br>  roles: [<br>    {<br>      roleName: &quot;readAnyDatabase&quot;,<br>      databaseName: &quot;admin&quot;,<br>    },<br>  ],<br>  scopes: [<br>    {<br>      name: atlasCluster.name,<br>      type: &quot;CLUSTER&quot;,<br>    },<br>  ],<br>});</pre><p>Environment variables that need to be set in the execution environment:</p><ul><li>TF_VAR_adminPassword</li></ul><p>Finally, let&#39;s add the remaining network access piece to our stack in main.ts:</p><pre>const userNetwork = new TerraformVariable(this, &quot;userNetwork&quot;, {<br>  type: &quot;string&quot;,<br>  description: &quot;MongoDB Atlas Project IP access&quot;,<br>  sensitive: false,<br>});<br><br>new ProjectIpAccessList(this, &quot;projectnetworkAccess&quot;, {<br>  projectId: atlasProject.id,<br>  cidrBlock: userNetwork.value, // secret set via environment variable TF_VAR_userNetwork<br>});</pre><p>Last but not least, define the one remaining env variable with your network CIDR.</p><p>Environment variables that need to be set in the execution environment:</p><ul><li>TF_VAR_userNetwork</li></ul><pre>cdktf plan<br>cdktf deploy</pre><p>And voila! We are now ready to start developing against our MongoDB Atlas cluster from our machine. Bon coding.</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=87adbf0252f4" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[AWS Amplify and AppSync with Expo (React Native) cheat sheet]]></title>
            <link>https://medium.com/@andrzejkomarnicki/aws-amplify-and-appsync-with-expo-react-native-cheat-sheet-423b189e088e?source=rss-4297e3e49338------2</link>
            <guid isPermaLink="false">https://medium.com/p/423b189e088e</guid>
            <category><![CDATA[react-native]]></category>
            <category><![CDATA[serverless]]></category>
            <category><![CDATA[aws]]></category>
            <category><![CDATA[mobile-app-development]]></category>
            <category><![CDATA[expo]]></category>
            <dc:creator><![CDATA[Andrzej Komarnicki]]></dc:creator>
            <pubDate>Mon, 17 Dec 2018 03:30:23 GMT</pubDate>
            <atom:updated>2020-03-19T04:05:26.586Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*Q0kFri-mPUsdHLmtqthLBA.jpeg" /></figure><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/d99ca875ebea5bef646a25549b21802d/href">https://medium.com/media/d99ca875ebea5bef646a25549b21802d/href</a></iframe><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=423b189e088e" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Exploring the Kubernetes API]]></title>
            <link>https://medium.com/@andrzejkomarnicki/exploring-the-kubernetes-api-8b0ee91cdfb7?source=rss-4297e3e49338------2</link>
            <guid isPermaLink="false">https://medium.com/p/8b0ee91cdfb7</guid>
            <category><![CDATA[development]]></category>
            <category><![CDATA[api]]></category>
            <category><![CDATA[cloud-computing]]></category>
            <category><![CDATA[kubernetes]]></category>
            <category><![CDATA[devops]]></category>
            <dc:creator><![CDATA[Andrzej Komarnicki]]></dc:creator>
            <pubDate>Wed, 31 Oct 2018 16:43:15 GMT</pubDate>
            <atom:updated>2020-03-19T04:06:41.824Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/198/1*uWJiBn1HWnd7udEZ6k-MzA.png" /></figure><h4>In this article we’re going to be using curl, kubectl proxy and the K8s API to answer the following questions:</h4><ul><li>Which namespaces are available in your config?</li><li>Which pods have been started in the kube-system namespace?</li><li>Which objects are available in the API v1 spec?</li><li>Request a full specification of an nginx pod</li></ul><p>If you’re running minikube or you are on a k8s node, you can check if kubectl proxy is running with ps axu | grep proxy otherwise just head straight to kubectl proxy --port=8001 and in a new shell type curl localhost:8001 which will show generic information about everything that is exposed. For instance curl localhost:8001/version will expose all the version info about your current cluster, in my case it shows the following:</p><pre>{<br>&quot;major&quot;: &quot;1&quot;,<br>&quot;minor&quot;: &quot;10+&quot;,<br>&quot;gitVersion&quot;: &quot;v1.10.3-eks&quot;,<br>&quot;gitCommit&quot;: &quot;58c199a59046dbf0a13a387d3491a39213be53df&quot;,<br>&quot;gitTreeState&quot;: &quot;clean&quot;,<br>&quot;buildDate&quot;: &quot;2018-09-21T21:00:04Z&quot;,<br>&quot;goVersion&quot;: &quot;go1.9.3&quot;,<br>&quot;compiler&quot;: &quot;gc&quot;,<br>&quot;platform&quot;: &quot;linux/amd64&quot;<br>}</pre><p>From this data you can clearly tell that I am running my cluster on Amazon EKS which is a managed Kubernetes service from AWS, while the version of K8s is 1.10.3 (at the time of this writing the latest supported version on EKS).</p><p>Now on to the really interesting stuff…let’s take a look at all of our namespaces via curl localhost:8001/api/v1/namespaces | grep -A 2 name</p><p>You’ll see something more less like this (along with whatever other namespaces you created):</p><pre>--<br>&quot;name&quot;: &quot;default&quot;,<br>&quot;selfLink&quot;: &quot;/api/v1/namespaces/default&quot;,<br>&quot;uid&quot;: &quot;d651faaa-a092-11e8-9b00-0a222b0de108&quot;,<br>&quot;resourceVersion&quot;: &quot;4&quot;,<br>--<br>&quot;name&quot;: &quot;kube-public&quot;,<br>&quot;selfLink&quot;: &quot;/api/v1/namespaces/kube-public&quot;,<br>&quot;uid&quot;: &quot;d8bc55f7-a092-11e8-9b00-0a222b0de108&quot;,<br>&quot;resourceVersion&quot;: &quot;16&quot;,<br>--<br>&quot;name&quot;: &quot;kube-system&quot;,<br>&quot;selfLink&quot;: &quot;/api/v1/namespaces/kube-system&quot;,<br>&quot;uid&quot;: &quot;d8bb77d6-a092-11e8-9b00-0a222b0de108&quot;,<br>&quot;resourceVersion&quot;: &quot;6665028&quot;,<br>--</pre><p>Now let’s see what pods are started in the kube-system namespace with the following command: curl localhost:8001/api/v1/namespaces/kube-system/pods | grep -A 2 metadata</p><pre>--<br>&quot;metadata&quot;: {<br>&quot;name&quot;: &quot;kube-proxy-nkbhg&quot;,<br>&quot;generateName&quot;: &quot;kube-proxy-&quot;,<br>--<br>&quot;metadata&quot;: {<br>&quot;name&quot;: &quot;kubernetes-dashboard-7d5dcdb6d9-xlk9t&quot;,<br>&quot;generateName&quot;: &quot;kubernetes-dashboard-7d5dcdb6d9-&quot;,<br>--<br>&quot;metadata&quot;: {<br>&quot;name&quot;: &quot;monitoring-influxdb-cc95575b9-4nsnh&quot;,<br>&quot;generateName&quot;: &quot;monitoring-influxdb-cc95575b9-&quot;,<br>--<br>&quot;metadata&quot;: {<br>&quot;name&quot;: &quot;my-nginx-77f56b88c8-6n6kv&quot;,<br>&quot;generateName&quot;: &quot;my-nginx-77f56b88c8-&quot;,<br>--</pre><p>You should see your pods displayed in a format as per above (you should also see <em>kube-dns</em>, and whatever other stuff you’ve loaded in there). If you want detailed info for all the pods you can use:</p><p>curl localhost:8001/api/v1/namespaces/kube-system/pods | less</p><blockquote>Exploring the different endpoints in the k8s API and how they are organized, including what objects and parameters are available, gives you a good idea as to how Kubernetes itself is internally structured and organized as well.</blockquote><p>Now the next question was, which objects are available in the <em>API v1 </em>specification? That’s an easy one, if we take everything out and just use this:</p><p>curl localhost:8001/api/v1/</p><p>We get the <em>object specification</em> along with the name, kind, and verb.</p><p>Here’s an example from the output:</p><pre>{<br> &quot;name&quot;: &quot;services&quot;,<br> &quot;singularName&quot;: &quot;&quot;,<br> &quot;namespaced&quot;: true,<br> &quot;kind&quot;: &quot;Service&quot;,<br> &quot;verbs&quot;: [<br> &quot;create&quot;,<br> &quot;delete&quot;,<br> &quot;get&quot;,<br> &quot;list&quot;,<br> &quot;patch&quot;,<br> &quot;update&quot;,<br> &quot;watch&quot;<br> ],<br> &quot;shortNames&quot;: [<br> &quot;svc&quot;<br> ],<br> &quot;categories&quot;: [<br> &quot;all&quot;<br> ]<br>},</pre><p>If you use curl localhost:8001/api/v1/ | grep name | less you can also see bindings, componentstatuses, configmaps, endpoints, events, and so on…</p><p>Now on to the last question, knowing what namespace you have deployed your nginx pod into and having retrieved the nginx pod name (or whatever other pod you want to explore) let’s take a look at it’s K8s API endpoint, which in my case is:</p><p>curl localhost:8001/api/v1/namespaces/kube-system/pods/my-nginx-77f56b88c8-6n6kv</p><pre>{<br> &quot;kind&quot;: &quot;Pod&quot;,<br> &quot;apiVersion&quot;: &quot;v1&quot;,<br> &quot;metadata&quot;: {<br>  &quot;name&quot;: &quot;my-nginx-77f56b88c8-6n6kv&quot;,<br>  &quot;generateName&quot;: &quot;my-nginx-77f56b88c8-&quot;,<br>  &quot;namespace&quot;: &quot;kube-system&quot;,<br>  &quot;selfLink&quot;: &quot;/api/v1/namespaces/kube-system/pods/my-nginx-77f56b88c8-6n6kv&quot;,<br>  &quot;uid&quot;: &quot;55c120c2-d865-11e8-a61b-125b96951d82&quot;,<br>  &quot;resourceVersion&quot;: &quot;10649474&quot;,<br>  &quot;creationTimestamp&quot;: &quot;2018-10-25T14:50:37Z&quot;,<br>  &quot;labels&quot;: {<br>   &quot;pod-template-hash&quot;: &quot;3391264474&quot;,<br>   &quot;run&quot;: &quot;my-nginx&quot;<br> },<br> &quot;ownerReferences&quot;: [<br>   {<br>    &quot;apiVersion&quot;: &quot;extensions/v1beta1&quot;,<br>    &quot;kind&quot;: &quot;ReplicaSet&quot;,<br>    &quot;name&quot;: &quot;my-nginx-77f56b88c8&quot;,<br>    &quot;uid&quot;: &quot;55bde0ea-d865-11e8-a61b-125b96951d82&quot;,<br>    &quot;controller&quot;: true,<br>    &quot;blockOwnerDeletion&quot;: true<br>   }<br>  ]<br> },<br> &quot;spec&quot;: {<br>   &quot;volumes&quot;: [<br>     {<br>       &quot;name&quot;: &quot;default-token-9qxrs&quot;,<br>       &quot;secret&quot;: {<br>         &quot;secretName&quot;: &quot;default-token-9qxrs&quot;,<br>         &quot;defaultMode&quot;: 420<br>       }<br>      }<br>    ],<br>    &quot;containers&quot;: [<br>     {<br>       &quot;name&quot;: &quot;my-nginx&quot;,<br>       &quot;image&quot;: &quot;nginx&quot;,<br>       &quot;ports&quot;: [ <br>        {<br>           &quot;containerPort&quot;: 80,<br>           &quot;protocol&quot;: &quot;TCP&quot;<br>        }<br>      ],<br>      &quot;resources&quot;: {<br>     <br>      },  <br>      &quot;volumeMounts&quot;: [<br>       {<br>         &quot;name&quot;: &quot;default-token-9qxrs&quot;,<br>         &quot;readOnly&quot;: true,<br>         &quot;mountPath&quot;: &quot;/var/run/secrets/kubernetes.io/serviceaccount&quot;<br>       }<br>     ],<br>     &quot;terminationMessagePath&quot;: &quot;/dev/termination-log&quot;,<br>     &quot;terminationMessagePolicy&quot;: &quot;File&quot;,<br>     &quot;imagePullPolicy&quot;: &quot;Always&quot;<br>    }<br>  ],<br>  &quot;restartPolicy&quot;: &quot;Always&quot;,<br>  &quot;terminationGracePeriodSeconds&quot;: 30,<br>  &quot;dnsPolicy&quot;: &quot;ClusterFirst&quot;,<br>  &quot;serviceAccountName&quot;: &quot;default&quot;,<br>  &quot;serviceAccount&quot;: &quot;default&quot;,<br>  &quot;nodeName&quot;: &quot;ip-10-0-1-112.ec2.internal&quot;,<br>  &quot;securityContext&quot;: {</pre><pre>  },<br>  &quot;schedulerName&quot;: &quot;default-scheduler&quot;,<br>  &quot;tolerations&quot;: [<br>    {<br>      &quot;key&quot;: &quot;node.kubernetes.io/not-ready&quot;,<br>      &quot;operator&quot;: &quot;Exists&quot;,<br>      &quot;effect&quot;: &quot;NoExecute&quot;,<br>      &quot;tolerationSeconds&quot;: 300<br>    },<br>    {<br>      &quot;key&quot;: &quot;node.kubernetes.io/unreachable&quot;,<br>      &quot;operator&quot;: &quot;Exists&quot;,<br>      &quot;effect&quot;: &quot;NoExecute&quot;,<br>      &quot;tolerationSeconds&quot;: 300<br>    }<br>  ]<br> },<br> &quot;status&quot;: {<br>  &quot;phase&quot;: &quot;Running&quot;,<br>  &quot;conditions&quot;: [<br>    {<br>      &quot;type&quot;: &quot;Initialized&quot;,<br>      &quot;status&quot;: &quot;True&quot;,<br>      &quot;lastProbeTime&quot;: null,<br>      &quot;lastTransitionTime&quot;: &quot;2018-10-25T14:50:37Z&quot;<br>    },<br>    {<br>      &quot;type&quot;: &quot;Ready&quot;,<br>      &quot;status&quot;: &quot;True&quot;,<br>      &quot;lastProbeTime&quot;: null,<br>      &quot;lastTransitionTime&quot;: &quot;2018-10-25T14:50:43Z&quot;<br>    },<br>    {<br>      &quot;type&quot;: &quot;PodScheduled&quot;,<br>      &quot;status&quot;: &quot;True&quot;,<br>      &quot;lastProbeTime&quot;: null,<br>      &quot;lastTransitionTime&quot;: &quot;2018-10-25T14:50:37Z&quot;<br>    }<br>   ],<br>   &quot;hostIP&quot;: &quot;10.0.1.112&quot;,<br>   &quot;podIP&quot;: &quot;10.0.1.232&quot;,<br>   &quot;startTime&quot;: &quot;2018-10-25T14:50:37Z&quot;,<br>   &quot;containerStatuses&quot;: [<br>    {<br>      &quot;name&quot;: &quot;my-nginx&quot;,<br>      &quot;state&quot;: {<br>      &quot;running&quot;: {<br>        &quot;startedAt&quot;: &quot;2018-10-25T14:50:43Z&quot;<br>      }<br>    },<br>    &quot;lastState&quot;: {</pre><pre>    },<br>    &quot;ready&quot;: true,<br>    &quot;restartCount&quot;: 0,<br>    &quot;image&quot;: &quot;nginx:latest&quot;,<br>    &quot;imageID&quot;: &quot;docker-pullable://nginx@sha256:b73f527d86e3461fd652f62cf47e7b375196063bbbd503e853af5be16597cb2e&quot;,<br>   &quot;containerID&quot;:<br>&quot;docker://9baf63301474ce5cddb37bd89c77785731221fedb1fb6d27e7a12c57c942f550&quot;<br>   }<br>  ],<br>  &quot;qosClass&quot;: &quot;BestEffort&quot;}<br> }<br>}</pre><p>So that concludes the scope of our journey, I hope you found it informative and now have a good idea as to how to navigate and query the Kubernetes API and are able to see how essential that practice can become especially when developing Kubernetes Operators and other Kubernetes Native applications or functions.</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=8b0ee91cdfb7" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Enforcing JWT (JSON Web Token) validation within Express.js routes]]></title>
            <link>https://medium.com/@andrzejkomarnicki/enforcing-jwt-json-web-token-verification-within-expressjs-routes-cdc46e6b2b6?source=rss-4297e3e49338------2</link>
            <guid isPermaLink="false">https://medium.com/p/cdc46e6b2b6</guid>
            <category><![CDATA[jwt]]></category>
            <category><![CDATA[javascript]]></category>
            <category><![CDATA[json]]></category>
            <category><![CDATA[expressjs]]></category>
            <category><![CDATA[nodejs]]></category>
            <dc:creator><![CDATA[Andrzej Komarnicki]]></dc:creator>
            <pubDate>Fri, 20 Apr 2018 04:03:47 GMT</pubDate>
            <atom:updated>2020-03-19T04:07:12.256Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/788/1*XkmnsJ6Joa6EDFVGUw0tfA.png" /><figcaption>source: http://atomrace.com/angular-jwt</figcaption></figure><p>Many people have surely heard about JSON (JavaScript Object Notation), the ubiquitous markup format for data-interchange, and some spectrum of those individuals have undoubtably also heard about JWT (JSON Web Token), which is a very useful open standard for securely transmitting data between parties in a self-contained way via JSON objects. Long story short, the token is comprised of a header, payload and secret and can be sent through a URL, POST or inside an HTTP header.</p><p>Say for instance you are developing a MEAN Stack-based Web App and want to make sure that only authenticated or logged-in users can post messages, you could for instance use JWT enforcement to protect all Expressjs routes except for:</p><pre>router.get(‘/’, function (req, res, next) {}) </pre><p>The ExpressJS <em>router.use()</em> method will allow you to execute a callback for every request other than the one above. The goal is to check if the client/browser is sending us a valid token. Given we are creating the token on the server and we know the logic behind the token, including the secret, we can easily validate the incoming token.</p><p>Assuming you’ve already installed the <a href="https://www.npmjs.com/package/jsonwebtoken"><strong>jsonwebtoken</strong></a><em> </em>package, and imported it via <em>require(‘jsonwebtoken’) </em>you can take the following approach<em>:</em></p><pre>router.use(&#39;/&#39;, function(req, res, next) {<br>    jwt.verify(req.query.token, &#39;secret&#39;, function(err, decoded) {<br>        if (err) {<br>            return res.status(401).json({<br>                title: &#39;Authentication failed&#39;,<br>                error: err<br>            });<br>        }<br>        next();<br>     })<br>});</pre><p><em>jwt.verify(req.query.token)</em> validates the query parameters for the token, and the <em>‘secret’</em> has to match the secret when the token is created. The callback is immediately passed with either an error or a decoded token. If we get an error it either means the token is expired or was never valid to begin with.</p><p>Happy JWTing!</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=cdc46e6b2b6" width="1" height="1" alt="">]]></content:encoded>
        </item>
    </channel>
</rss>