<?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: Vipin Vijaykumar</title>
    <description>The latest articles on DEV Community by Vipin Vijaykumar (@vipinvkmenon).</description>
    <link>https://dev.to/vipinvkmenon</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%2F268178%2F3a8d5833-cb9e-4958-b940-39ff5aad5528.jpeg</url>
      <title>DEV Community: Vipin Vijaykumar</title>
      <link>https://dev.to/vipinvkmenon</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/vipinvkmenon"/>
    <language>en</language>
    <item>
      <title>Bye-Bye Credentials! Automate BTP &amp; Cloud Foundry Setup with Terraform using Github Actions and Github OIDC</title>
      <dc:creator>Vipin Vijaykumar</dc:creator>
      <pubDate>Wed, 13 Aug 2025 15:38:36 +0000</pubDate>
      <link>https://dev.to/vipinvkmenon/bye-bye-credentials-automate-btp-cloud-foundry-setup-with-terraform-using-github-actions-and-3m07</link>
      <guid>https://dev.to/vipinvkmenon/bye-bye-credentials-automate-btp-cloud-foundry-setup-with-terraform-using-github-actions-and-3m07</guid>
      <description>&lt;p&gt;&lt;strong&gt;Imagine this&lt;/strong&gt;: You want to automate setting up SAP BTP Accounts and Cloud Foundry using Terraform, but without the pain of managing and tracking usernames, passwords, or rotating any of those credentials.&lt;/p&gt;

&lt;p&gt;Well, that's no longer a dream! Most common CI/CD Solutions like &lt;a href="https://docs.github.com/en/actions/how-tos/secure-your-work/security-harden-deployments/oidc-in-cloud-providers" rel="noopener noreferrer"&gt;Github&lt;/a&gt;/&lt;a href="https://docs.gitlab.com/integration/openid_connect_provider/" rel="noopener noreferrer"&gt;Gitlab&lt;/a&gt; actions, &lt;a href="https://plugins.jenkins.io/oidc-provider/" rel="noopener noreferrer"&gt;Jenkins&lt;/a&gt;, &lt;a href="https://devblogs.microsoft.com/devops/workload-identity-federation-for-azure-deployments-is-now-generally-available/" rel="noopener noreferrer"&gt;Azure&lt;/a&gt; &lt;a href="https://devblogs.microsoft.com/devops/introduction-to-azure-devops-workload-identity-federation-oidc-with-terraform/" rel="noopener noreferrer"&gt;DevOps&lt;/a&gt; etc and OIDC Provider integration, you can wave goodbye to maintaining long-lived credentials. Say hello to &lt;strong&gt;short-lived, secure, just-in-time&lt;/strong&gt; tokens.&lt;/p&gt;

&lt;p&gt;In this blog, we’ll set up GitHub’s OIDC provider to authenticate directly against SAP BTP using &lt;strong&gt;JWT Bearer Assertion flow&lt;/strong&gt;, and then use Terraform to provision your &lt;a href="https://www.sap.com/india/products/technology-platform.html" rel="noopener noreferrer"&gt;BTP&lt;/a&gt; resources, &lt;a href="https://www.cloudfoundry.org/" rel="noopener noreferrer"&gt;Cloud Foundry&lt;/a&gt; spaces, and more. These steps work for both &lt;a href="https://developer.hashicorp.com/terraform" rel="noopener noreferrer"&gt;Terraform&lt;/a&gt; and &lt;a href="https://opentofu.org/" rel="noopener noreferrer"&gt;OpenTofu&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What's a JWT Bearer Assertion Anyway?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Before we jump into Terraform and GitHub Actions, let’s talk &lt;a href="https://www.jwt.io/introduction#what-is-json-web-token" rel="noopener noreferrer"&gt;JWT Bearer tokens&lt;/a&gt;. A JWT Bearer Assertion is a way for a client to prove its identity to an authorisation server using a signed JSON Web Token (JWT) instead of a password or traditional credentials. Since the tokens are short-lived and ephemeral, they bring somewhat better security and rotation.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;In short&lt;/strong&gt;: Instead of passing around long-term credentials, GitHub can request a short-lived token for your pipeline, signed and trusted via OpenID Connect. This token is accepted by an &lt;a href="https://help.sap.com/docs/cloud-identity-services/cloud-identity-services/landing-page" rel="noopener noreferrer"&gt;SAP Cloud Identity Service&lt;/a&gt; tenant, which then lets Terraform (on behalf of GitHub Actions) access BTP and Cloud Foundry APIs.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Event Sequence&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Github Workflow is triggered&lt;/li&gt;
&lt;li&gt;The Github OIDC Provider is called, and a JWT Token is generated for the workflow. This token is stored in environment variables or github variables&lt;/li&gt;
&lt;li&gt;The JWT Bearer token is used by the BTP &amp;amp; CF terraform provider in the Terraform scripts&lt;/li&gt;
&lt;li&gt;The calls for the respective providers are authenticated in BTP and CF (UAA) via the trusted SAP Cloud Identity Service tenant. The bearer token is forwarded to the SAP Cloud Identity Service&lt;/li&gt;
&lt;li&gt;SAP Cloud Identity services validate the token against the Github OIDC Public Keys(JWKS)&lt;/li&gt;
&lt;li&gt;If the key is successfully validated, the clients are authenticated, and subsequent calls can be made.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Let’s dig in!
&lt;/h2&gt;

&lt;p&gt;This tutorial builds upon &lt;a href="https://community.sap.com/t5/technology-blog-posts-by-sap/authenticating-github-actions-workflows-deploying-to-the-sap-btp-cloud/ba-p/14075047" rel="noopener noreferrer"&gt;a community blog&lt;/a&gt; that showcases how the &lt;code&gt;cf&lt;/code&gt; CLI can leverage GitHub OIDC for logging into and managing Cloud Foundry. &lt;/p&gt;

&lt;p&gt;We'll reference the community blog for the initial setup steps as it's well-documented there. &lt;/p&gt;

&lt;h3&gt;
  
  
  Step 1: Establish Trust between SAP BTP &amp;amp; SAP Cloud Identity Services
&lt;/h3&gt;

&lt;p&gt;Please refer to the &lt;a href="https://help.sap.com/docs/btp/sap-business-technology-platform/establish-trust-and-federation-of-custom-identity-providers-for-platform-users?locale=en-US#procedure" rel="noopener noreferrer"&gt;official documentation&lt;/a&gt; for doing the same&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 2: Create the Github Repo
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Create the github repo with &lt;code&gt;repository-name&lt;/code&gt; in the &lt;code&gt;Organisation&lt;/code&gt; you need. &lt;strong&gt;This repository and name will be used in the next steps&lt;/strong&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Step 3:Configure SAP Cloud Identity Services
&lt;/h3&gt;

&lt;p&gt;In this step, configure the SAP Cloud Identity Services to&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Add the Repo User for Github Action Workflows. 
Note: 

&lt;ul&gt;
&lt;li&gt;Name format: &lt;code&gt;repo/&amp;lt;Organisation&amp;gt;/&amp;lt;repository-name&amp;gt;&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Email format: &lt;code&gt;repo/&amp;lt;Organisation&amp;gt;/&amp;lt;repository-name&amp;gt;@&amp;lt;github-domain&amp;gt;&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;Add the Repo User to a group&lt;/li&gt;

&lt;li&gt;Configure Github OIDC as a Corporate IdP&lt;/li&gt;

&lt;li&gt;Map the repository name as &lt;code&gt;NameId&lt;/code&gt; (Enriched Token Claims)&lt;/li&gt;

&lt;li&gt;Configure Identity Federation.&lt;/li&gt;

&lt;li&gt;Set up the BTP Application to use the GitHub IDP&lt;/li&gt;

&lt;/ul&gt;

&lt;p&gt;Please refer to the &lt;a href="https://community.sap.com/t5/technology-blog-posts-by-sap/authenticating-github-actions-workflows-deploying-to-the-sap-btp-cloud/ba-p/14075047" rel="noopener noreferrer"&gt;community blog&lt;/a&gt; mentioned above for the detailed steps with regards to this.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 4: Add user to Global Account
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Add the &lt;code&gt;repo-user&lt;/code&gt; email, created in SAP Cloud Identity Services in BTP. &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.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%2Fjjdd7h3k3pd832fzyt8m.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.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%2Fjjdd7h3k3pd832fzyt8m.png" alt=" " width="800" height="461"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Since we will be working with creating a subaccount and managing resources at the Global Account level, assign the &lt;code&gt;Global Account Administrator&lt;/code&gt; Role Collection.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.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%2Fca0cm6om7gyb2ob8mehg.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.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%2Fca0cm6om7gyb2ob8mehg.png" alt=" " width="800" height="491"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 5: Add content to the Github Repository
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;The following will be the structure of the project and files.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&amp;lt;repository-root-directory&amp;gt;/
├── .github
│   └── workflows
│       └── deploy.yml
├── main.tf
├── provider.tf
├── terraform.tfvars
└── variables.tf
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Here we create a Terraform configuration that uses the Terraform providers for SAP BTP &amp;amp; Cloud Foundry to:-&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Add the configuration to initialise the &lt;code&gt;provider.tf&lt;/code&gt; file&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  &lt;code&gt;main.tf&lt;/code&gt;
&lt;/h4&gt;

&lt;p&gt;The &lt;code&gt;main.tf&lt;/code&gt; has the definition of the infrastructure that will be created. For this article, we take a simple scenario as:-&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Create a Subaccount&lt;/li&gt;
&lt;li&gt;Initialise a Cloud Foundry Runtime Environment in the subaccount&lt;/li&gt;
&lt;li&gt;Create a space within Cloud Foundry&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This would, of course vary depending on your setup and scenario. So we won't delve into this section much.&lt;/p&gt;

&lt;p&gt;For details on the different resources &amp;amp; datasources present in the Terraform providers for &lt;a href="https://registry.terraform.io/providers/SAP/btp/latest" rel="noopener noreferrer"&gt;SAP BTP&lt;/a&gt; &amp;amp; &lt;a href="https://registry.terraform.io/providers/cloudfoundry/cloudfoundry/latest" rel="noopener noreferrer"&gt;Cloud Foundry&lt;/a&gt;, please refer to the registry.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight hcl"&gt;&lt;code&gt;&lt;span class="nx"&gt;resource&lt;/span&gt; &lt;span class="s2"&gt;"btp_subaccount"&lt;/span&gt; &lt;span class="s2"&gt;"project"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;name&lt;/span&gt;      &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"sample project"&lt;/span&gt;
  &lt;span class="nx"&gt;subdomain&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"sample.project"&lt;/span&gt;
  &lt;span class="nx"&gt;region&lt;/span&gt;    &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;lower&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;var&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;region&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nx"&gt;resource&lt;/span&gt; &lt;span class="s2"&gt;"btp_subaccount_environment_instance"&lt;/span&gt; &lt;span class="s2"&gt;"cloudfoundry"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;subaccount_id&lt;/span&gt;    &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;btp_subaccount&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;project&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;
  &lt;span class="nx"&gt;name&lt;/span&gt;             &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"sample-cf-instance"&lt;/span&gt;
  &lt;span class="nx"&gt;landscape_label&lt;/span&gt;  &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"cf-ap10"&lt;/span&gt;
  &lt;span class="nx"&gt;environment_type&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"cloudfoundry"&lt;/span&gt;
  &lt;span class="nx"&gt;service_name&lt;/span&gt;     &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"cloudfoundry"&lt;/span&gt;
  &lt;span class="nx"&gt;plan_name&lt;/span&gt;        &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"standard"&lt;/span&gt;
  &lt;span class="nx"&gt;parameters&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;jsonencode&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="nx"&gt;instance_name&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"sample-cf-instance"&lt;/span&gt;
  &lt;span class="p"&gt;})&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nx"&gt;resource&lt;/span&gt; &lt;span class="s2"&gt;"cloudfoundry_space"&lt;/span&gt; &lt;span class="s2"&gt;"space"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;name&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"dev_space"&lt;/span&gt;
  &lt;span class="nx"&gt;org&lt;/span&gt;  &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;btp_subaccount_environment_instance&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;cloudfoundry&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;platform_id&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  &lt;code&gt;variables.tf&lt;/code&gt; file
&lt;/h4&gt;

&lt;p&gt;Here we declare the variables &lt;code&gt;globalaccount&lt;/code&gt; and &lt;code&gt;idp&lt;/code&gt;. You'd have more depending on your script.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight hcl"&gt;&lt;code&gt;&lt;span class="nx"&gt;variable&lt;/span&gt; &lt;span class="s2"&gt;"globalaccount"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;type&lt;/span&gt;        &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;string&lt;/span&gt;
  &lt;span class="nx"&gt;description&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"The subdomain of the SAP BTP global account."&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nx"&gt;variable&lt;/span&gt; &lt;span class="s2"&gt;"idp"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;type&lt;/span&gt;        &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;string&lt;/span&gt;
  &lt;span class="nx"&gt;description&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"Orgin key of Identity Provider"&lt;/span&gt;
  &lt;span class="nx"&gt;default&lt;/span&gt;     &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Configure &lt;code&gt;provider.tf&lt;/code&gt;
&lt;/h4&gt;

&lt;p&gt;By convention, the &lt;code&gt;provider.tf&lt;/code&gt; file usually represents the configuration to initialise the providers. Here we will configure the SAP BTP and Cloud Foundry providers.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight hcl"&gt;&lt;code&gt;&lt;span class="nx"&gt;terraform&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;required_providers&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;btp&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;source&lt;/span&gt;  &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"sap/btp"&lt;/span&gt;
      &lt;span class="nx"&gt;version&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"~&amp;gt; 1.15.0"&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="nx"&gt;cloudfoundry&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;source&lt;/span&gt;  &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"cloudfoundry/cloudfoundry"&lt;/span&gt;
      &lt;span class="nx"&gt;version&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"~&amp;gt; 1.8.0"&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nx"&gt;provider&lt;/span&gt; &lt;span class="s2"&gt;"btp"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;globalaccount&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;var&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;globalaccount&lt;/span&gt;
  &lt;span class="nx"&gt;idp&lt;/span&gt;           &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;var&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;idp&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="nx"&gt;provider&lt;/span&gt; &lt;span class="s2"&gt;"cloudfoundry"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;api_url&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"https://api.cf.${var.region}.hana.ondemand.com"&lt;/span&gt;
  &lt;span class="nx"&gt;origin&lt;/span&gt;  &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;var&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;idp&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;As can be seen:-&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;btp&lt;/code&gt; provider is configured with the &lt;code&gt;global&lt;/code&gt; account and the    &lt;code&gt;idp&lt;/code&gt; (Based on the trust configured in the above steps)&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;cloudfoundry&lt;/code&gt; is configured with the &lt;code&gt;cf-api&lt;/code&gt; and the &lt;code&gt;origin&lt;/code&gt;(uaa), which is the same trust configuration as created above&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Since the credentials used here is the assertion token, we'll be using the environment variables BTP_ASSERTION and CF_ASSERTION_TOKEN.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Note&lt;/strong&gt;:- &lt;em&gt;CF API depends on the region where the subaccount is created. Please refer to the right API in the&lt;/em&gt; &lt;a href="https://help.sap.com/docs/btp/sap-business-technology-%20platform/regions-and-api-endpoints-available-for-cloud-foundry-%20environment?locale=en-US" rel="noopener noreferrer"&gt;official document&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 6: Add the Github Workflow
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;The Github workflow initialises Terraform, generates the token and stores it as Github Outputs. These tokens are then assigned as environment variables to the Terraform Providers. Thereafter, the Terraform executes the scripts just as any typical workflow.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Deploy&lt;/span&gt;
&lt;span class="na"&gt;on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;workflow_dispatch&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;inputs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;region&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;description&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;BTP&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;Subaccount&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;Region'&lt;/span&gt;
        &lt;span class="na"&gt;required&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
        &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;string&lt;/span&gt;
      &lt;span class="na"&gt;idp&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;description&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;Identity&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;Provider'&lt;/span&gt;
        &lt;span class="na"&gt;required&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
        &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;string&lt;/span&gt;
      &lt;span class="na"&gt;global_account_id&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;description&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;Global&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;Account&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;ID'&lt;/span&gt;
        &lt;span class="na"&gt;required&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
        &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;string&lt;/span&gt;
      &lt;span class="na"&gt;tenantIssuerUri&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;description&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;Issuer&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;URL'&lt;/span&gt;
        &lt;span class="na"&gt;required&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
        &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;string&lt;/span&gt;
&lt;span class="na"&gt;jobs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;deploy&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;runs-on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;ubuntu-latest&lt;/span&gt;
    &lt;span class="na"&gt;permissions&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;id-token&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;write&lt;/span&gt; &lt;span class="c1"&gt;# This is required for requesting the JWT&lt;/span&gt;
        &lt;span class="na"&gt;contents&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;read&lt;/span&gt;
    &lt;span class="na"&gt;steps&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Checkout code&lt;/span&gt;
        &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;actions/checkout@v2&lt;/span&gt;

      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Set up Terraform&lt;/span&gt;
        &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;hashicorp/setup-terraform@v1&lt;/span&gt;
        &lt;span class="na"&gt;with&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;terraform_wrapper&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;
          &lt;span class="na"&gt;terraform_version&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;latest&lt;/span&gt;

      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Install OIDC Client from Core Package&lt;/span&gt;
        &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;npm install @actions/core @actions/http-client&lt;/span&gt;

      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Get Id Token&lt;/span&gt;
        &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;actions/github-script@v7&lt;/span&gt;
        &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;idtoken&lt;/span&gt;
        &lt;span class="na"&gt;env&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;TENANT_URL&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${{inputs.tenantIssuerUri}}&lt;/span&gt;
        &lt;span class="na"&gt;with&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;script&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;|&lt;/span&gt;
            &lt;span class="s"&gt;const tenanturl = process.env.TENANT_URL;&lt;/span&gt;
            &lt;span class="s"&gt;const coredemo = require('@actions/core')&lt;/span&gt;
            &lt;span class="s"&gt;let id_token = await coredemo.getIDToken(tenanturl)&lt;/span&gt;
            &lt;span class="s"&gt;coredemo.setOutput('githubJwt', id_token)&lt;/span&gt;

      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Apply Terraform configuration&lt;/span&gt;
        &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;|&lt;/span&gt;
          &lt;span class="s"&gt;export BTP_ASSERTION="${{ steps.idtoken.outputs.githubJwt }}"&lt;/span&gt;
          &lt;span class="s"&gt;export CF_ASSERTION_TOKEN="${{ steps.idtoken.outputs.githubJwt }}"&lt;/span&gt;
          &lt;span class="s"&gt;terraform apply -auto-approve -var "region=${{ inputs.region }}" -var "idp=${{ inputs.idp }}" -var "globalaccount=${{ inputs.global_account_id }}"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For this article, the workflow is triggered &lt;a href="https://docs.github.com/en/actions/reference/workflows-and-actions/events-that-trigger-workflows#workflow_dispatch" rel="noopener noreferrer"&gt;manually&lt;/a&gt; based on user inputs. It takes the following inputs:-&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;BTP Subaccount Region&lt;/strong&gt;: Region where the Subaccount will be created&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Identity Provider&lt;/strong&gt;: The name of the identity provider (Origin Key (Cloud Foundry)) that was configured in the Trust Configuration in BTP from the above step.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Global Account ID&lt;/strong&gt;: The Global Account Subdomain&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Issuer URL&lt;/strong&gt;: The URL of the SAP Cloud Identity Service Tenant. 
Github OIDC Provider issues tokens for this tenant as the &lt;a href="https://www.ory.sh/docs/hydra/guides/audiences" rel="noopener noreferrer"&gt;audience&lt;/a&gt;. &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The token is generated in the step &lt;code&gt;Get Id Token&lt;/code&gt;. In this article, we use the &lt;a href="https://github.com/actions/toolkit/tree/main/packages/core" rel="noopener noreferrer"&gt;core package&lt;/a&gt; for the GH Actions Toolkit. An alternative approach of using &lt;a href="https://docs.github.com/en/actions/how-tos/secure-your-work/security-harden-deployments/oidc-in-cloud-providers#requesting-the-jwt-using-environment-variables" rel="noopener noreferrer"&gt;curl&lt;/a&gt;. This approach can be seen in the blog referred above.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 7: Trigger Workflow
&lt;/h3&gt;

&lt;p&gt;Trigger the workflow from the Github Actions tab. Add the necessary details as seen below.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.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%2Fvo1ofmt0dndd4zb2t313.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.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%2Fvo1ofmt0dndd4zb2t313.png" alt=" " width="700" height="1002"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The Job should run successfully, whereby you can see that the Token is generated and used by the subsequent steps.&lt;/p&gt;

&lt;h3&gt;
  
  
  Conclusion
&lt;/h3&gt;

&lt;p&gt;By federating GitHub Actions with SAP Cloud Identity and leveraging the JWT Bearer Assertion flow, you can automate provisioning of SAP BTP resources and Cloud Foundry environments without storing or rotating long-lived service credentials. &lt;/p&gt;

&lt;h3&gt;
  
  
  Some Best Practices
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Use any supported remote, encrypted Terraform/OpenTofu backends&lt;/strong&gt; like &lt;a href="https://developer.hashicorp.com/hcp" rel="noopener noreferrer"&gt;HCP&lt;/a&gt;, &lt;a href="https://www.hashicorp.com/en/products/vault" rel="noopener noreferrer"&gt;Vault&lt;/a&gt;, &lt;a href="https://openbao.org/" rel="noopener noreferrer"&gt;OpenBao&lt;/a&gt;, S3/GCS/Azure Blob, etc, with server-side encryption. &lt;/li&gt;
&lt;li&gt;Work with &lt;strong&gt;least privilege &amp;amp; role collections&lt;/strong&gt;: In BTP, assign the repo user (or group) only the role collections needed for the automation (For e.g Avoid Global Account Admin if the setup is for a specific subaccount).&lt;/li&gt;
&lt;li&gt;Ensure &lt;strong&gt;GitHub Repo is protected&lt;/strong&gt; and &lt;strong&gt;require reviewers&lt;/strong&gt; for workflows that can create or alter infrastructure.&lt;/li&gt;
&lt;li&gt;Test your workflow setup on dev/test environments first.&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>terraform</category>
      <category>github</category>
      <category>devops</category>
      <category>btp</category>
    </item>
    <item>
      <title>Setting up OTEL Collectors for mTLS</title>
      <dc:creator>Vipin Vijaykumar</dc:creator>
      <pubDate>Mon, 17 Feb 2025 03:27:47 +0000</pubDate>
      <link>https://dev.to/vipinvkmenon/setting-up-otel-collectors-for-mtls-4n4o</link>
      <guid>https://dev.to/vipinvkmenon/setting-up-otel-collectors-for-mtls-4n4o</guid>
      <description>&lt;h1&gt;
  
  
  What's mTLS
&lt;/h1&gt;

&lt;p&gt;&lt;strong&gt;mTLS&lt;/strong&gt; (Mutual Transport Layer Security) is an enhanced version of &lt;strong&gt;TLS&lt;/strong&gt; (Transport Layer Security) where the client and the server authenticate each other during the connection establishment.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;A very Simple Flow for mTLS. (Note arrow direction)

+--------+ ---1--&amp;gt; +--------+
| Client | &amp;lt;--2--- | Server |
+--------+ &amp;lt;--3--&amp;gt; +--------+

1a) Client sends request to server along with its certificate.
1b) Server verifies the client certificate using client's public key.(Server has the public Key in its store/DB)
2a) Server sends response along with its certificate.
2b) Client verifies the server certificate with the server public key
3) After mutual authentication, encrypted communication between client and server.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Typically, the server and client certificates are signed by a CA. As the server can manage multiple clients, the server usually maintains the public key of the CA that is used to sign all clients.&lt;/p&gt;

&lt;h1&gt;
  
  
  How is this different from regular TLS?
&lt;/h1&gt;

&lt;p&gt;Regular TLS is unidirectional. I.E Only the client verifies the certificates presented by the server. The server does not verify the client's certificates.&lt;/p&gt;

&lt;h1&gt;
  
  
  Using mTLS in OpenTelemetry(OTEL)
&lt;/h1&gt;

&lt;p&gt;To use mTLS between 2 OTEL components, we need client and server certificates.&lt;/p&gt;

&lt;h2&gt;
  
  
  Scenario
&lt;/h2&gt;

&lt;p&gt;2 OTEL Collectors. One as client (exporter) and the other as server (receiver). Metrics are sent/forwarded from the client to the server. Since this is a demo setup (or internal) we will be using Self Signed certificates.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;+-------------+                       +--------------+
| Otel Client |-------GRPC-----------&amp;gt;|  OTEL Server |
| (Exporter)  |                       |  (Receiver)  |
+-------------+                       +--------------+
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We'll be running this inside a Kubernetes cluster in 2 different namespaces.&lt;/p&gt;

&lt;p&gt;&lt;u&gt;Prerequisites&lt;/u&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A Kubernetes cluster&lt;/li&gt;
&lt;li&gt;kubectl &amp;amp; helm&lt;/li&gt;
&lt;li&gt;System with OpenSSL client installed&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Demo
&lt;/h2&gt;

&lt;h3&gt;
  
  
  1) Generate certificates
&lt;/h3&gt;

&lt;p&gt;a)&lt;u&gt;Generate rootCA certificate.&lt;/u&gt;&lt;br&gt;
Since we are using Self-signed certificates, we will create and use our own rootCA.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;openssl req &lt;span class="nt"&gt;-x509&lt;/span&gt; &lt;span class="nt"&gt;-sha256&lt;/span&gt; &lt;span class="nt"&gt;-nodes&lt;/span&gt; &lt;span class="nt"&gt;-days&lt;/span&gt; 365 &lt;span class="nt"&gt;-newkey&lt;/span&gt; rsa:4096 &lt;span class="nt"&gt;-subj&lt;/span&gt; &lt;span class="s1"&gt;'/O=A Team/CN=root.com'&lt;/span&gt; &lt;span class="nt"&gt;-keyout&lt;/span&gt; rootCA.key &lt;span class="nt"&gt;-out&lt;/span&gt; rootCA.pem
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;b)&lt;u&gt;Generate server certificate&lt;/u&gt;&lt;br&gt;
We need to first create a &lt;code&gt;certificate signing request (csr)&lt;/code&gt; for the server certificate: &lt;code&gt;server.csr&lt;/code&gt; and the key &lt;code&gt;server.key&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;openssl req &lt;span class="nt"&gt;-out&lt;/span&gt; server.csr &lt;span class="nt"&gt;-newkey&lt;/span&gt; rsa:4096 &lt;span class="nt"&gt;-nodes&lt;/span&gt; &lt;span class="nt"&gt;-keyout&lt;/span&gt; server.key &lt;span class="nt"&gt;-subj&lt;/span&gt; &lt;span class="s2"&gt;"/CN=test.com/O=PM"&lt;/span&gt; &lt;span class="nt"&gt;-config&lt;/span&gt; server.cnf &lt;span class="nt"&gt;-extensions&lt;/span&gt; req_ext
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You will notice a &lt;code&gt;server.cnf&lt;/code&gt; config file. This file consists of extensions for adding Subject Alternative Names (&lt;code&gt;SAN&lt;/code&gt;), which are alternative host names that can identify the server.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;[req]
default_bits = 4096
prompt = no
default_md = sha256
req_extensions = req_ext
distinguished_name = dn
[ dn ]
CN = 'test.com'
[ req_ext ]
subjectAltName = @alt_names
[alt_names]
DNS.1   = 'test.com'
DNS.2   = 'test.server.svc.cluster.local'
DNS.3   = 'localhost'
DNS.4   = 'test'
# add more for other names
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We will then use the &lt;code&gt;server.csr&lt;/code&gt; to create a signed server certificate: &lt;code&gt;server.pem&lt;/code&gt;. The signing is done by the &lt;code&gt;rootCA&lt;/code&gt; certificate that was generated in &lt;code&gt;step a&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;openssl x509 &lt;span class="nt"&gt;-req&lt;/span&gt; &lt;span class="nt"&gt;-sha256&lt;/span&gt; &lt;span class="nt"&gt;-days&lt;/span&gt; 365 &lt;span class="nt"&gt;-CA&lt;/span&gt; rootCA.pem &lt;span class="nt"&gt;-CAkey&lt;/span&gt; rootCA.key &lt;span class="nt"&gt;-CAcreateserial&lt;/span&gt; &lt;span class="nt"&gt;-in&lt;/span&gt; server.csr &lt;span class="nt"&gt;-out&lt;/span&gt; server.pem &lt;span class="nt"&gt;-extensions&lt;/span&gt; req_ext &lt;span class="nt"&gt;-extfile&lt;/span&gt; server.cnf
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;em&gt;Notice: We use the &lt;code&gt;rootCA&lt;/code&gt; certificate and private key to sign the certificate.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;b)&lt;u&gt;Generate client certificate&lt;/u&gt;&lt;br&gt;
Similarly, we create client certificates &amp;amp; key: &lt;code&gt;client.pem&lt;/code&gt;| &lt;code&gt;client.key&lt;/code&gt;. For the ease of this demo , we use the same &lt;code&gt;rootCA&lt;/code&gt; to sign the client certificates.&lt;/p&gt;

&lt;p&gt;As before we use a &lt;code&gt;client.cnf&lt;/code&gt; also maintained for &lt;code&gt;SAN&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;[req]
default_bits = 4096
prompt = no
default_md = sha256
req_extensions = req_ext
distinguished_name = dn
[ dn ]
CN = 'localhost'
[ req_ext ]
subjectAltName = @alt_names
[alt_names]
DNS.1   = 'localhost' 
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Creating the &lt;code&gt;csr&lt;/code&gt; and signing it with the &lt;code&gt;rootCA&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;openssl req &lt;span class="nt"&gt;-out&lt;/span&gt; client.csr &lt;span class="nt"&gt;-newkey&lt;/span&gt; rsa:4096 &lt;span class="nt"&gt;-nodes&lt;/span&gt; &lt;span class="nt"&gt;-keyout&lt;/span&gt; client.key &lt;span class="nt"&gt;-subj&lt;/span&gt; &lt;span class="s2"&gt;"/CN=localhost/O=client"&lt;/span&gt; &lt;span class="nt"&gt;-extensions&lt;/span&gt; req_ext &lt;span class="nt"&gt;-config&lt;/span&gt; client.cnf

openssl x509 &lt;span class="nt"&gt;-req&lt;/span&gt; &lt;span class="nt"&gt;-sha256&lt;/span&gt; &lt;span class="nt"&gt;-days&lt;/span&gt; 365 &lt;span class="nt"&gt;-CA&lt;/span&gt; rootCA.pem &lt;span class="nt"&gt;-CAkey&lt;/span&gt; rootCA.key &lt;span class="nt"&gt;-CAcreateserial&lt;/span&gt; &lt;span class="nt"&gt;-in&lt;/span&gt; client.csr &lt;span class="nt"&gt;-out&lt;/span&gt; client.pem &lt;span class="nt"&gt;-extensions&lt;/span&gt; req_ext &lt;span class="nt"&gt;-extfile&lt;/span&gt; client.cnf
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  1) Deploy on Kubernetes
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Prerequisite&lt;/strong&gt;: Please install the &lt;a href="https://opentelemetry.io/docs/platforms/kubernetes/operator/" rel="noopener noreferrer"&gt;opentelemetry-operator&lt;/a&gt; in the cluster.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;helm repo add open-telemetry https://open-telemetry.github.io/opentelemetry-helm-charts

helm &lt;span class="nb"&gt;install &lt;/span&gt;otel-operator open-telemetry/opentelemetry-operator &lt;span class="nt"&gt;--namespace&lt;/span&gt; otel-collector-operator &lt;span class="nt"&gt;--create-namespace&lt;/span&gt; &lt;span class="nt"&gt;--set&lt;/span&gt; &lt;span class="s2"&gt;"manager.collectorImage.repository=otel/opentelemetry-collector-k8s"&lt;/span&gt; &lt;span class="nt"&gt;--set&lt;/span&gt; admissionWebhooks.certManager.enabled&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nb"&gt;false&lt;/span&gt; &lt;span class="nt"&gt;--set&lt;/span&gt; admissionWebhooks.autoGenerateCert.enabled&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nb"&gt;true&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;a)&lt;u&gt;Create namespaces&lt;/u&gt;&lt;br&gt;
Create the 2 namespaces&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl create ns server
kubectl create ns client
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;b)&lt;u&gt;Create Kubernetes secrets.&lt;/u&gt;&lt;br&gt;
The certificates that were generated in &lt;strong&gt;step 1&lt;/strong&gt; will be used to create the secrets. These secrets will be mounted into the OTEL pods in the next step.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;k create secret generic server &lt;span class="nt"&gt;-n&lt;/span&gt; server  &lt;span class="nt"&gt;--from-file&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;tls.pem&lt;span class="o"&gt;=&lt;/span&gt;server.pem &lt;span class="nt"&gt;--from-file&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;tls.key&lt;span class="o"&gt;=&lt;/span&gt;server.key &lt;span class="nt"&gt;--from-file&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;ca.pem&lt;span class="o"&gt;=&lt;/span&gt;rootCA.pem &lt;span class="c"&gt;# server certificates&lt;/span&gt;

k create secret generic client &lt;span class="nt"&gt;-n&lt;/span&gt; client  &lt;span class="nt"&gt;--from-file&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;tls.pem&lt;span class="o"&gt;=&lt;/span&gt;client.pem &lt;span class="nt"&gt;--from-file&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;tls.key&lt;span class="o"&gt;=&lt;/span&gt;client.key &lt;span class="nt"&gt;--from-file&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;ca.pem&lt;span class="o"&gt;=&lt;/span&gt;rootCA.pem &lt;span class="c"&gt;# client certificates&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;c)&lt;u&gt;Deploy the OTEL Receiver (server)&lt;/u&gt;&lt;br&gt;
The OTEL receiver is the server that accepts the metrics. For our demo purpose the OTEL server will receive the metrics (Port 4317) and print it in the logs. The server is deployed in &lt;code&gt;server&lt;/code&gt; namespace and the secrets are mounted as volume to be used by the otel-collector receiver.&lt;/p&gt;

&lt;p&gt;We also create a service named test with port 4317. While this is optional for the demo, its a good practice. Additionally certain meshes..For E.g istio relies on the port &lt;code&gt;name&lt;/code&gt; for the protocol. (&lt;code&gt;grpc&lt;/code&gt; is the name of the port in the service here)&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;apiVersion&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;opentelemetry.io/v1alpha1&lt;/span&gt;
&lt;span class="na"&gt;kind&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;OpenTelemetryCollector&lt;/span&gt;
&lt;span class="na"&gt;metadata&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;test&lt;/span&gt;
  &lt;span class="na"&gt;namespace&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;server&lt;/span&gt;
  &lt;span class="na"&gt;labels&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;app&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;otel-collector&lt;/span&gt;
&lt;span class="na"&gt;spec&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;mode&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;deployment&lt;/span&gt;
  &lt;span class="na"&gt;volumeMounts&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;server&lt;/span&gt;
    &lt;span class="na"&gt;mountPath&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;/etc/pki/ca-trust/source/server-ca&lt;/span&gt;
    &lt;span class="na"&gt;readOnly&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
  &lt;span class="na"&gt;volumes&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;server&lt;/span&gt;
    &lt;span class="na"&gt;secret&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;secretName&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;server&lt;/span&gt;
  &lt;span class="na"&gt;config&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;|&lt;/span&gt;
    &lt;span class="s"&gt;receivers:&lt;/span&gt;
      &lt;span class="s"&gt;otlp:&lt;/span&gt;
        &lt;span class="s"&gt;protocols:&lt;/span&gt;
          &lt;span class="s"&gt;grpc:&lt;/span&gt;
            &lt;span class="s"&gt;#endpoint: test.server.svc.cluster.local:4317&lt;/span&gt;
            &lt;span class="s"&gt;tls:&lt;/span&gt;
              &lt;span class="s"&gt;cert_file: /etc/pki/ca-trust/source/server-ca/tls.pem&lt;/span&gt;
              &lt;span class="s"&gt;key_file: /etc/pki/ca-trust/source/server-ca/tls.key&lt;/span&gt;
              &lt;span class="s"&gt;client_ca_file: /etc/pki/ca-trust/source/server-ca/ca.pem&lt;/span&gt;
    &lt;span class="s"&gt;exporters:&lt;/span&gt;
      &lt;span class="s"&gt;# NOTE: Prior to v0.86.0 use `logging` instead of `debug`.&lt;/span&gt;
      &lt;span class="s"&gt;debug:&lt;/span&gt;
        &lt;span class="s"&gt;verbosity: detailed&lt;/span&gt;
    &lt;span class="s"&gt;service:&lt;/span&gt;
      &lt;span class="s"&gt;pipelines:&lt;/span&gt;
        &lt;span class="s"&gt;metrics:&lt;/span&gt;
          &lt;span class="s"&gt;receivers: [otlp]&lt;/span&gt;
          &lt;span class="s"&gt;processors: []&lt;/span&gt;
          &lt;span class="s"&gt;exporters: [debug]&lt;/span&gt;
&lt;span class="s"&gt;---&lt;/span&gt;
&lt;span class="na"&gt;apiVersion&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;v1&lt;/span&gt;
&lt;span class="na"&gt;kind&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Service&lt;/span&gt;
&lt;span class="na"&gt;metadata&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;test&lt;/span&gt;
  &lt;span class="na"&gt;namespace&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;test&lt;/span&gt;
&lt;span class="na"&gt;spec&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;selector&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;app.kubernetes.io/component&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;opentelemetry-collector&lt;/span&gt;
    &lt;span class="na"&gt;app.kubernetes.io/instance&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;test.test&lt;/span&gt;
    &lt;span class="na"&gt;app.kubernetes.io/name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;test-collector&lt;/span&gt;
  &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;ClusterIP&lt;/span&gt;
  &lt;span class="na"&gt;ports&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;grpc&lt;/span&gt; &lt;span class="c1"&gt;# important for istio!&lt;/span&gt;
    &lt;span class="na"&gt;protocol&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;TCP&lt;/span&gt;
    &lt;span class="na"&gt;port&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;4317&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Verify the otel-collector instance and service is created&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl get pods,svc &lt;span class="nt"&gt;-n&lt;/span&gt; server
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;b)&lt;u&gt;Deploy the OTEL Exporter (client)&lt;/u&gt;&lt;br&gt;
The OTEL Exporter is the client that generates (i.e source) the metrics. We use the &lt;a href="https://github.com/open-telemetry/opentelemetry-collector-contrib/blob/main/receiver/hostmetricsreceiver/README.md" rel="noopener noreferrer"&gt;hostmetrics&lt;/a&gt; receiver plugin. This will vary according to the needs.&lt;br&gt;
The other receiver is deployed in the &lt;code&gt;client&lt;/code&gt; namespace. The client certificates are mounted as &lt;code&gt;volumeMounts&lt;/code&gt; just as before.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;apiVersion&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;opentelemetry.io/v1alpha1&lt;/span&gt;
&lt;span class="na"&gt;kind&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;OpenTelemetryCollector&lt;/span&gt;
&lt;span class="na"&gt;metadata&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;client&lt;/span&gt;
  &lt;span class="na"&gt;namespace&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;client&lt;/span&gt;
  &lt;span class="na"&gt;labels&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;app&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;client&lt;/span&gt;
&lt;span class="na"&gt;spec&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;mode&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;deployment&lt;/span&gt;
  &lt;span class="na"&gt;volumeMounts&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;client&lt;/span&gt;
    &lt;span class="na"&gt;mountPath&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;/etc/pki/ca-trust/source/client-ca&lt;/span&gt;
    &lt;span class="na"&gt;readOnly&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
  &lt;span class="na"&gt;volumes&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;client&lt;/span&gt;
    &lt;span class="na"&gt;secret&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;secretName&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;client&lt;/span&gt;
  &lt;span class="na"&gt;config&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;|&lt;/span&gt;
    &lt;span class="s"&gt;receivers:&lt;/span&gt;
      &lt;span class="s"&gt;# Data sources: metrics&lt;/span&gt;
      &lt;span class="s"&gt;hostmetrics:&lt;/span&gt;
        &lt;span class="s"&gt;scrapers:&lt;/span&gt;
          &lt;span class="s"&gt;cpu:&lt;/span&gt;
          &lt;span class="s"&gt;disk:&lt;/span&gt;
    &lt;span class="s"&gt;processors:&lt;/span&gt;
      &lt;span class="s"&gt;# Data sources: traces&lt;/span&gt;
      &lt;span class="s"&gt;attributes:&lt;/span&gt;
        &lt;span class="s"&gt;actions:&lt;/span&gt;
          &lt;span class="s"&gt;- key: environment&lt;/span&gt;
            &lt;span class="s"&gt;value: external-test-3&lt;/span&gt;
            &lt;span class="s"&gt;action: insert&lt;/span&gt;
      &lt;span class="s"&gt;# Data sources: traces, metrics, logs&lt;/span&gt;
    &lt;span class="s"&gt;exporters:&lt;/span&gt;
      &lt;span class="s"&gt;otlp:&lt;/span&gt;
        &lt;span class="s"&gt;endpoint: test.server.svc.cluster.local:4317&lt;/span&gt;
        &lt;span class="s"&gt;tls:&lt;/span&gt;
          &lt;span class="s"&gt;ca_file: /etc/pki/ca-trust/source/client-ca/ca.pem&lt;/span&gt;
          &lt;span class="s"&gt;cert_file: /etc/pki/ca-trust/source/client-ca/tls.pem&lt;/span&gt;
          &lt;span class="s"&gt;key_file: /etc/pki/ca-trust/source/client-ca/tls.key&lt;/span&gt;
      &lt;span class="s"&gt;debug: #just to print metrics in logs of the client&lt;/span&gt;
    &lt;span class="s"&gt;service:&lt;/span&gt;
      &lt;span class="s"&gt;pipelines:&lt;/span&gt;
        &lt;span class="s"&gt;metrics:&lt;/span&gt;
          &lt;span class="s"&gt;receivers: [hostmetrics]&lt;/span&gt;
          &lt;span class="s"&gt;processors: [attributes]&lt;/span&gt;
          &lt;span class="s"&gt;exporters: [otlp,debug]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Verify the otelcollector instance is created&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl get pods &lt;span class="nt"&gt;-n&lt;/span&gt; client
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;c) &lt;u&gt;Verify the setup&lt;/u&gt;&lt;br&gt;
Check the logs of the server otel (receiver). You should see logs of metrics generated by the client otel (exporter).&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl logs &lt;span class="nt"&gt;-f&lt;/span&gt; &amp;lt;otel-receiver-pod&amp;gt; &lt;span class="nt"&gt;-n&lt;/span&gt; server
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



</description>
      <category>mtls</category>
      <category>opentelemetry</category>
      <category>kubernetes</category>
      <category>observability</category>
    </item>
    <item>
      <title>Accessing Privileged Containers in Cloud Foundry: A Guide</title>
      <dc:creator>Vipin Vijaykumar</dc:creator>
      <pubDate>Thu, 19 Dec 2024 09:28:25 +0000</pubDate>
      <link>https://dev.to/vipinvkmenon/accessing-privileged-containers-in-cloud-foundry-a-guide-5fim</link>
      <guid>https://dev.to/vipinvkmenon/accessing-privileged-containers-in-cloud-foundry-a-guide-5fim</guid>
      <description>&lt;p&gt;&lt;strong&gt;Usually, your productive apps don’t and shouldn't have SSH access in Cloud Foundry.&lt;/strong&gt; However, you might need to SSH into an application for debugging purposes. Fortunately, this is achievable by enabling the SSH permission for both the &lt;a href="https://cli.cloudfoundry.org/en-US/v6/allow-space-ssh.html" rel="noopener noreferrer"&gt;space&lt;/a&gt; and the &lt;a href="https://docs.cloudfoundry.org/devguide/deploy-apps/ssh-apps.html#enable-disable-ssh" rel="noopener noreferrer"&gt;app&lt;/a&gt; and be &lt;a href="https://docs.cloudfoundry.org/running/config-ssh.html" rel="noopener noreferrer"&gt;enabled by the operator&lt;/a&gt;, after which you can use the cf ssh command. This approach suffices for most scenarios.&lt;/p&gt;

&lt;p&gt;But sometimes, this level of access isn’t enough. You might require privileged access to the application container for advanced troubleshooting or debugging. Why might you need this? That’s a question only you can answer, but this blog will show you how it’s done.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note&lt;/strong&gt;: &lt;em&gt;This process can only be executed if you are an operator of the Cloud Foundry deployment and can access the Diego cells.&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;strong&gt;Steps to Gain Privileged Access&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Retrieve the app-guid for the application
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;cf app &amp;lt;app-name&amp;gt; --guid
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;Log in to BOSH and target the Cloud Foundry deployment
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;bosh -d cf vms
bosh -d cf ssh &amp;lt;diego-cell&amp;gt;  #(any Diego cell)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;Use the cfdot utility to locate application details&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;In Diego terms, applications are referred to as “lrps” (long-running processes). Using the app-guid, identify the lrp instance_id and the diego_cell where the application or process is running.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;cfdot actual-lrps | grep -E '&amp;lt;app-guid&amp;gt;' | jq -r '. | select(.index == 0)' # Index 0 is for the 0th instance of the application.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This command will provide the instance_guid and cell_id of the application container.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;SSH into the respective Diego Cell
From the cell_id identified in the previous step, SSH into the corresponding Diego Cell.
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;bosh -d cf ssh &amp;lt;diego_cell&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;Attach to the Garden container
You can attach it to the container using one of two methods:&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Approach 1: Using &lt;code&gt;runc&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;sudo /var/vcap/packages/runc/bin/runc --root /run/containerd/runc/garden/ exec &amp;lt;instance_guid&amp;gt; --tty /bin/sh
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Approach 2: Using ctr&lt;br&gt;
This approach is not recommended as the &lt;code&gt;ctr&lt;/code&gt; command line is not actively maintained and the commands may vary over time.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;sudo /var/vcap/packages/containerd/bin/ctr -a /var/vcap/sys/run/containerd/containerd.sock -n garden tasks exec --exec-id my-shell --tty &amp;lt;instance_guid&amp;gt; /bin/sh
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;After running either of these commands, you will have privileged access to the application container.&lt;/p&gt;




&lt;p&gt;&lt;strong&gt;! A Word of Caution !&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;With great power comes great responsibility. &lt;br&gt;
Privileged access should be used sparingly and responsibly if possible NEVER. Always assess the necessity of these steps, and avoid this process unless required. &lt;br&gt;
Things can break here if you are NOT careful!&lt;/p&gt;




&lt;p&gt;&lt;em&gt;I've messed up something what do I do&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Fear not. Mostly deleting the app instance can reset and set things back to usual.&lt;/p&gt;

</description>
      <category>cloudfoundry</category>
      <category>containers</category>
      <category>linux</category>
      <category>cloud</category>
    </item>
    <item>
      <title>How to get into an app container manually in Cloud Foundry with Garden-Containerd Backend</title>
      <dc:creator>Vipin Vijaykumar</dc:creator>
      <pubDate>Mon, 18 Nov 2019 09:54:26 +0000</pubDate>
      <link>https://dev.to/vipinvkmenon/how-to-get-into-an-app-container-manually-in-cloud-foundry-with-garden-containerd-backend-23l3</link>
      <guid>https://dev.to/vipinvkmenon/how-to-get-into-an-app-container-manually-in-cloud-foundry-with-garden-containerd-backend-23l3</guid>
      <description>&lt;h2&gt;
  
  
  Summary
&lt;/h2&gt;

&lt;p&gt;A method to get into a container on the Diego Cell&lt;/p&gt;

&lt;h2&gt;
  
  
  Purpose
&lt;/h2&gt;

&lt;p&gt;The requirement is to be able to access the application container in Cloud Foundry in scenarios where cf ssh  would not be possible. Main reasons being troubleshooting inside the container. This write-up describes the procedures for the same. The original article for containers based on garden-runc is provided below.&lt;/p&gt;

&lt;h2&gt;
  
  
  Procedure
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Obtain the app &lt;code&gt;process-guid&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;cf curl /v2/apps/$(cf app &amp;lt;app-name&amp;gt; --guid)| jq -r '.metadata.guid + "-" + .entity.version'
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;Obtain the hosts in which the app is running. Choose one of the I
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;cf curl v2/apps/$(cf app &amp;lt;app-name&amp;gt; --guid)/stats | grep host
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Login to the bosh director.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Identify the cell/VM Instance name associated to the IP&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;SSH into the VM&lt;br&gt;
&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;bosh -e &amp;lt;environment&amp;gt; -d &amp;lt;deployment&amp;gt; ssh &amp;lt;Instance-Name&amp;gt;
diego-cell/8cbe944d-d0cc-4158-802e-59426506faf7:~$ sudo -i
diego-cell/8cbe944d-d0cc-4158-802e-59426506faf7:~#
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;Obtain the "instance_guid"   for the process-guid from step 1
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;cfdot actual-lrp-groups | grep d7c18647-9560-4327-8bcc-b7ab1ecdf295-2d6ebf81-7857-46d8-8bdc-f958795abf86
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;Attach into the container using ctr  (containerd client)
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;export containerid=&amp;lt;Instance_Guid_&amp;gt;
/var/vcap/packages/containerd/bin/ctr -a /var/vcap/sys/run/containerd/containerd.sock -n garden tasks exec --exec-id my-shell --tty $containerd /bin/bash
root@9b5900f2-34f3-4317-63bb-863c:/#
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;You will now be in the container.&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>cloudfoundry</category>
      <category>docker</category>
      <category>cloud</category>
      <category>bosh</category>
    </item>
  </channel>
</rss>
