<?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: gvelrajan</title>
    <description>The latest articles on DEV Community by gvelrajan (@gvelrajan).</description>
    <link>https://dev.to/gvelrajan</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%2F410660%2Fed2fdc2e-a866-4f4c-b643-266165ecca4f.png</url>
      <title>DEV Community: gvelrajan</title>
      <link>https://dev.to/gvelrajan</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/gvelrajan"/>
    <language>en</language>
    <item>
      <title>How to configure and setup SSH certificates for SSH authentication</title>
      <dc:creator>gvelrajan</dc:creator>
      <pubDate>Thu, 10 Mar 2022 05:53:27 +0000</pubDate>
      <link>https://dev.to/gvelrajan/how-to-configure-and-setup-ssh-certificates-for-ssh-authentication-b52</link>
      <guid>https://dev.to/gvelrajan/how-to-configure-and-setup-ssh-certificates-for-ssh-authentication-b52</guid>
      <description>&lt;p&gt;SSH public key based authentication has several drawbacks and operational challenges that could potentially compromise your organization’s SSH access security. We discussed the drawbacks in detail in our earlier blog on: &lt;a href="https://www.bastionxp.com/blog/tightening-ssh-access-using-short-lived-ssh-certificates/"&gt;Tightening SSH access using short-lived SSH certificates&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;SSH certificate based authentication addresses most of these security problems while simplifying certificate and key management.&lt;/p&gt;

&lt;p&gt;In this article, we’ll discuss how to configure and set up SSH certificates for SSH access to your servers and cloud resources.&lt;/p&gt;

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

&lt;p&gt;Here is an overview of what we are about to discuss in this article.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;We’ll be creating two SSH Certificate Authorities(CA) - a host CA and a user CA, to sign the SSH host certificates and user certificates respectively. (Note: You can create just a single CA to sign both user and host certificates. But it is better to keep them separate, so that you could rotate them separately when the situation warrants.)&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;We’ll show how to configure the host and user machines to trust certificates issued by these host and user CAs.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;We’ll be creating an SSH host certificate for each host and sign it using the host CA’s private key.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;We’ll be creating an SSH user certificate for each user and sign it using the user CA’s private key.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Finally, we’ll discuss the benefits and drawbacks of using SSH certificate based authentication.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Step 1 - Creating CA certificates
&lt;/h2&gt;

&lt;p&gt;Before we could create the CA certificates, we needed an SSH key pair to work with. We’ll be using the ssh-keygen tool to generate an SSH key pair, as usual. We’ll be executing the following set of commands on the server designated to be the CA.&lt;/p&gt;

&lt;h3&gt;
  
  
  User CA SSH key pair:
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# ssh-keygen -t rsa -b 4096 -f ~/.ssh/ssh_user_ca

Generating public/private rsa key pair.
Enter passphrase (empty for no passphrase): 
Enter same passphrase again: 
Your identification has been saved in /root/.ssh/ssh_user_ca
Your public key has been saved in /root/.ssh/ssh_user_ca.pub
The key fingerprint is:
SHA256:ShpCF11/fYjujAVDYivNKpNM6QdVwh8Z9sX00PIspdo 
The key's randomart image is:
+---[RSA 4096]----+
|    .oooBo.o+.   |
|     +o*o* .o=o. |
|  . = ..+.= o*+ .|
| . = o o.  =o o. |
|  . B + S  oo.   |
|   . B .  .=Z    |
|    . .   . o    |
|                 |
|                 |
+----[SHA256]-----+
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Host CA SSH key pair:
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# ssh-keygen -t rsa -b 4096 -f ~/.ssh/ssh_host_ca
Generating public/private rsa key pair.
Enter passphrase (empty for no passphrase): 
Enter same passphrase again: 
Your identification has been saved in /root/.ssh/ssh_host_ca
Your public key has been saved in /root/.ssh/ssh_host_ca.pub
The key fingerprint is:
SHA256:ShpCF11/fYjujAVDYivNKpNM6QdVwh8Z9sX00PIadsfj 
The key's randomart image is:
+---[RSA 4096]----+
|    .oooBo.o+.   |
|     +o*o* .o=o. |
|  . = ..+.= o*+ .|
| . = o o.  =o o. |
|  . B + S  oo.   |
|   . B .  .=F    |
|    . .   . o    |
|                 |
|                 |
+----[SHA256]-----+
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We are requesting an RSA type key using the -t flag and the key length to be 4096 bits using the -b flag. The longer the key, the harder it is to crack.&lt;/p&gt;

&lt;p&gt;It is highly recommended to provide a passphrase for the private key. If an unauthorized user gets hold of the private key with no passphrase, they will be able to log in to any server you’ve configured with the associated public key.&lt;/p&gt;

&lt;p&gt;The above command would have generated an SSH pair - public key and a private key, in the default .ssh folder in your home directory. For example: &lt;code&gt;/home/bob/.ssh/&lt;/code&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 1a - Signing the CA’s Host Certificate
&lt;/h3&gt;

&lt;p&gt;Now, using the following command, let’s create the host CA’s certificate using the host public key and sign it using the corresponding host private key generated in the previous step.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# ssh-keygen -s ~/.ssh/ssh_host_ca -I my-ca -h -n my-ca.example.com -V +52w ~/.ssh/ssh_host_ca.pub  
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The -s specifies the host private key to be used for signing the certificate. The -h option is used for generating a host type certificate.&lt;/p&gt;

&lt;p&gt;The -n option above sets the FQDN (Fully Qualified Domain Name) of the host as the principals in the certificate.&lt;/p&gt;

&lt;p&gt;The -V option sets the validity period of the certificate.&lt;/p&gt;

&lt;p&gt;In the example above, the certificate will be valid from today and expires one year (52 weeks) from now.&lt;/p&gt;

&lt;p&gt;You can verify the details of the certificate using the following command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# ssh-keygen -Lf ~/.ssh/ssh_host_ca-cert.pub
/root/.ssh/ssh_host_ca-cert.pub:
        Type: ssh-rsa host certificate
        Public key: RSA-CERT SHA256:7sCdBjn0...
        Signing CA: RSA SHA256:7sCdBjn0... (using rsa-sha2-512)
        Key ID: "my-ca"
        Serial: 0
        Valid: from 2022-02-12T10:09:00 to 2023-02-11T10:10:29
        Principals: 
                my-ca.example.com
        Critical Options: (none)
        Extensions: (none)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Copy the CA’s host certificate to the &lt;code&gt;/etc/ssh/&lt;/code&gt; folder in the CA server.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 2 - Distributing and trusting the CA certificates
&lt;/h2&gt;

&lt;p&gt;We need to copy the user CA certificate to all the hosts in the organization. This is to make the hosts trust the user certificate’s signing authority.&lt;/p&gt;

&lt;p&gt;Similarly we need to copy the host CA certificate to all the user’s machines. This is to make the ssh clients in the user’s machine trust the host certificate’s signing authority.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 2a - Making hosts to trust user CA certificate
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# scp ~/.ssh/ssh_user_ca.pub root@host1.example.com:/etc/ssh/
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Next edit the SSH server config file at &lt;code&gt;/etc/ssh/sshd_config&lt;/code&gt; and make the &lt;code&gt;TrustedUserCAKeys&lt;/code&gt; directive to point to the user CA public key (NOT the user CA certificate) we just copied over.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;TrustedUserCAKeys /etc/ssh/ssh_user_ca.pub
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Restart the host to make the config change to take effect.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# systemctl restart sshd
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Step 2b - Making clients to trust the host CA certificate
&lt;/h3&gt;

&lt;p&gt;For this, you need to copy the contents of the host CA certificate and append it to the &lt;code&gt;/etc/ssh/ssh_known_hosts&lt;/code&gt; file using the &lt;code&gt;@cert-authority&lt;/code&gt; directive as shown below.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# cat /etc/ssh/ssh_host_ca-cert.pub
ssh-rsa AAAAHHNzaC1yc2EtY2....  root@example.com
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now copy this content to the SSH global config file &lt;code&gt;ssh_known_hosts&lt;/code&gt; in all the user systems.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# nano /etc/ssh/ssh_known_hosts
@cert-authority *.example.com ssh-rsa AAAAHHNzaC1yc2EtY2....  root@example.com
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;*.example.com&lt;/code&gt; wildcard entry above instructs the user systems to trust the host certificates received from any hosts in the &lt;code&gt;example.com&lt;/code&gt; domain, signed by the host CA.&lt;/p&gt;

&lt;p&gt;Now that we have the host and user CA certificates in place, we are ready to issue SSH certificates to hosts and user machines using them. Let’s see how to issue the host certificate first.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 3 - Creating SSH Host Certificates
&lt;/h2&gt;

&lt;p&gt;To create the host certificate, we needed an SSH key pair to work with. Let’s create one as usual using the &lt;code&gt;ssh-keygen&lt;/code&gt; command. Login to the host machine that needs the certificate and execute the below command.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# ssh-keygen -t rsa -b 4096 -f ~/.ssh/ssh_host
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The above command will generate a public key (&lt;code&gt;ssh_host.pub&lt;/code&gt;) and a private key (&lt;code&gt;ssh_host&lt;/code&gt;) in the .ssh folder in the home directory (&lt;code&gt;/root/.ssh/&lt;/code&gt;).&lt;/p&gt;

&lt;p&gt;You should retain the private key safely within the host system. You should never copy or transfer the file to any other location.&lt;/p&gt;

&lt;p&gt;We’ll copy just the host public key the CA server using the scp command as shown below:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# scp /root/.ssh/ssh_host.pub root@my-ca:/root/tmp/
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Next, create the host certificate from the host public key and sign the certificate using the host CA’s private key.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# ssh-keygen -s ~/.ssh/ssh_host_ca -I host1@example.com -h -n host1.example.com -V +52w /root/tmp/ssh_host.pub
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Once signed, copy the host SSH certificate (&lt;code&gt;ssh_host-cert.pub&lt;/code&gt;) to the host machine using the scp command. It is safe to copy SSH certificates around because they are public objects and can be shared with anyone.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# scp /root/tmp/ssh_host-cert.pub  root@host1.example.com:/etc/ssh/
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now configure the host to use the signed host certificate for any connections coming from the SSH clients. Edit the &lt;code&gt;/etc/ssh/sshd_config&lt;/code&gt; file and set the HostCertificate directive to point to the host certificate as shown below:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# nano /etc/ssh/ssh_config
…
HostCertificate  /etc/ssh/ssh_host-cert.pub
…
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Finally, restart the SSH server for the configuration changes to take effect.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# systemctl restart sshd
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Step 4 - Creating SSH User Certificates
&lt;/h2&gt;

&lt;p&gt;First, let’s create an SSH key pair for the user certificate as usual.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# ssh-keygen -t rsa -b 4096 -f ~/.ssh/ssh_user
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Next, we should copy the user public key to the CA server for signing it.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# scp ~/.ssh/ssh_user.pub  /root/tmp/.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Login to the CA server and sign the user certificate using the user CA’s private key as shown below:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# ssh-keygen -s ~/.ssh/ssh_user_ca -I bob@example.com  -n root -V +4w /root/tmp/ssh_user.pub
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Secure copy the signed user certificate back to the user machine.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# scp /root/tmp/ssh_user-cert.pub bob@user1.example.com:~/.ssh/.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Next edit the ssh client config file &lt;code&gt;/etc/ssh/ssh_config&lt;/code&gt;(global config file) or &lt;code&gt;~/.ssh/config&lt;/code&gt; file (local config file) in the user’s home directory and add the following line to it, so that SSH client will be able to automatically pick up the user’s private key file and the certificate during authentication.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;IdentityFile ~/.ssh/ssh_user
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Note that the &lt;code&gt;IdentityFile&lt;/code&gt; directive is made to point to the user’s private key and not the public key or the certificate.&lt;/p&gt;

&lt;p&gt;Try login to the host machine from the user machine to verify that everything is set properly and working just fine&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ ssh bob@host1.example.com
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Delete any existing public key for this host from the &lt;code&gt;~/.ssh/known_hosts&lt;/code&gt; file in the user machine, if required, to prevent the SSH client from complaining about the host key has changed.&lt;/p&gt;

&lt;p&gt;The host public key in the &lt;code&gt;~/.ssh/known_hosts&lt;/code&gt; file is irrelevant for SSH certificate based authentication because it uses the host CA certificate to validate the signature in the host certificate.&lt;/p&gt;

&lt;h2&gt;
  
  
  Benefits of using SSH certificate based authentication:
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;SSH certificates have a validity period, so user and host certificates expire eventually sometime in the future.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;User certificates need not be copied to all the host machines.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Short-lived SSH certificates can be issued to users to access privileged resources.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;No more weird messages (about recognizing and accepting the host key fingerprint) shown by the SSH client when login to the host machines for the first time.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;When a security compromise is detected, invalidate the old CA, create a new CA and issue new certificates to hosts and users. This is called as certificate rotation.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Drawbacks of using SSH certificate based authentication:
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Certificates need to be rotated periodically with proper planning and resource allocation&lt;/li&gt;
&lt;li&gt;Short-lived user certificates are great for privileged access to production resources. However, issuing user certificates more frequently and copying them to the user machines is still a laborious process.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  What is BastionXP Bastion Host Solution
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://www.bastionxp.com"&gt;BastionXP Bastion Host solution&lt;/a&gt; with built-in Public Key Infrastructure(PKI) and Certificate Authority(CA), automates and simplifies the certificate creation, signing and distribution process at scale. &lt;/p&gt;

&lt;p&gt;It also automates the ability to rotate certificates when situation warrants. BastionXP Bastion Host PKI/CA also issues short-lived user certificates to end users to access cloud resources or on-prem servers. Moreover, the solution works seamlessly with OpenSSH server and clients.&lt;/p&gt;

&lt;p&gt;So when a privileged user leaves an organization, you don’t need to clean up the public keys or certificates in your host machines because we don’t copy them to the host machines in the first place under the SSH certificate based authentication method.&lt;/p&gt;

&lt;p&gt;Moreover, the privileged user’s short-lived certificates would have expired by the time he/she leaves the office on the last day of work.&lt;/p&gt;

&lt;p&gt;Learn more about BastionXP Bastion Host solution and start your free trial here:&lt;br&gt;
&lt;a href="https://www.bastionxp.com"&gt;https://www.bastionxp.com&lt;/a&gt;&lt;/p&gt;

</description>
      <category>ssh</category>
      <category>sshcertificate</category>
      <category>sshpublickey</category>
      <category>bastionhost</category>
    </item>
    <item>
      <title>How to configure and setup SSH public keys, the right way</title>
      <dc:creator>gvelrajan</dc:creator>
      <pubDate>Thu, 10 Mar 2022 05:01:46 +0000</pubDate>
      <link>https://dev.to/gvelrajan/how-to-configure-and-setup-ssh-public-keys-the-right-way-23be</link>
      <guid>https://dev.to/gvelrajan/how-to-configure-and-setup-ssh-public-keys-the-right-way-23be</guid>
      <description>&lt;p&gt;Mostly, users login to their servers using SSH passwords. SSH password based authentication is not safe for enterprise use cases because passwords are usually short in length, contain dictionary words, and can be easily guessed. Using SSH public key based authentication is safe for enterprise deployments.&lt;/p&gt;

&lt;p&gt;In this article we’ll discuss &lt;a href="https://www.bastionxp.com/blog/how-to-configure-and-setup-ssh-public-keys-the-right-way/"&gt;how to configure and setup SSH public key based login for a linux server&lt;/a&gt;.  &lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; There are several security problems &amp;amp; operational challenges associated with using SSH public key based authentication and SSH key management tools. We discuss this in great detail in our next article here: &lt;a href="https://www.bastionxp.com/blog/tightening-ssh-access-using-short-lived-ssh-certificates/"&gt;Tightening SSH access using short-lived SSH certificates&lt;/a&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Step #1 Create the SSH keys
&lt;/h2&gt;

&lt;p&gt;When you install SSH, it comes with a bunch of handy tools. One of them is named ssh-keygen. We’ll use ssh-keygen to create SSH public keys.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;ssh-keygen &lt;span class="nt"&gt;-t&lt;/span&gt; rsa &lt;span class="nt"&gt;-b&lt;/span&gt; 4096
Generating public/private rsa key pair.
Enter file &lt;span class="k"&gt;in &lt;/span&gt;which to save the key &lt;span class="o"&gt;(&lt;/span&gt;/home/bob/.ssh/id_rsa&lt;span class="o"&gt;)&lt;/span&gt;: 
Enter passphrase &lt;span class="o"&gt;(&lt;/span&gt;empty &lt;span class="k"&gt;for &lt;/span&gt;no passphrase&lt;span class="o"&gt;)&lt;/span&gt;: 
Enter same passphrase again: 
Your identification has been saved &lt;span class="k"&gt;in&lt;/span&gt; /home/bob/.ssh/id_rsa
Your public key has been saved &lt;span class="k"&gt;in&lt;/span&gt; /home/bob/.ssh/id_rsa.pub
The key fingerprint is:
SHA256:ShpCF11/fYjujAVDYivNKpNM6QdVwh8Z9sX00PIspdo 
bob@localhost
The key&lt;span class="s1"&gt;'s randomart image is:
+---[RSA 4096]----+
|    .oooBo.o+.   |
|     +o*o* .o=o. |
|  . = ..+.= o*+ .|
| . = o o.  =o o. |
|  . B + S  oo.   |
|   . B .  .=E    |
|    . .   . o    |
|                 |
|                 |
+----[SHA256]-----+
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We are requesting a RSA type key and the key length should be 4096 bits. The longer the key, the harder it is to crack it.&lt;/p&gt;

&lt;p&gt;It is highly recommended to provide a passphrase for the private key, when prompted. If an unauthorized user gets hold of the private key with no passphrase, they will be able to log in to any server you’ve configured with the associated public key.&lt;/p&gt;

&lt;p&gt;The above command would have generated an SSH pair - public key and a private key, in the default .ssh folder in your home directory. For example: &lt;code&gt;/home/bob/.ssh/&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Public Key:&lt;/strong&gt; /home/bob/.ssh/id_rsa.pub &lt;br&gt;
&lt;strong&gt;Private Key:&lt;/strong&gt; /home/bob/.ssh/id_rsa&lt;/p&gt;

&lt;p&gt;You should neither share the private key with anyone nor copy it to your online storage or emails or chat window.&lt;/p&gt;
&lt;h2&gt;
  
  
  Step 2: Configure the server to use the public key
&lt;/h2&gt;

&lt;p&gt;Next, we need to copy the SSH public key to the server. We’ll use a tool named ssh-copy-id that is part of the ssh toolkit.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;ssh-copy-id bob@server-name 
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Once the above command completes, you can login to your server using the SSH public key. If you have set up a passphrase during the key generation, the ssh-copy-id command will ask for it. Alternatively, you can copy the SSH public key manually to the server. You need to copy-paste or append the public key to the &lt;code&gt;~/.ssh/authorized_keys&lt;/code&gt; file on the server.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;&lt;span class="nb"&gt;cat&lt;/span&gt; /home/bob/.ssh/authorized_keys 
&lt;span class="c"&gt;#Bob's key&lt;/span&gt;
ssh-rsa AAAAB3NzaC1yc2EAAAADAQAB... bob
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Step 3 Verify SSH login using the key
&lt;/h2&gt;

&lt;p&gt;Verify if you can login to the server using the ssh key generated above. Run the SSH client command as shown below:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;ssh &lt;span class="nt"&gt;-i&lt;/span&gt; /home/bob/.ssh/id_rsa bob@server-name
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The -i option is used to specify the identity file or the SSH private key file. You may be prompted for the passphrase to unlock the private key, if you provided one during the step #1 above.&lt;/p&gt;

&lt;p&gt;When you login using the SSH key for the first time, you’ll see a weird message on the console, something like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;The authenticity of host &lt;span class="s1"&gt;'server-name (10.1.1.1)'&lt;/span&gt; can&lt;span class="s1"&gt;'t be established.
ED25519 key fingerprint is SHA256:LKVs+g5kgmIXsYkU2Fl8XmNOmW4Rz1/AoXBLdRoanzM.
This key is not known by any other names
Are you sure you want to continue connecting (yes/no/[fingerprint])?
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is a catch22 situation where you can neither deny nor agree with the message. If you know this is your host or server, then say yes and continue. The SSH public key of the host will be stored in the &lt;code&gt;~/.ssh/known_hosts&lt;/code&gt; file in your client machine for future reference. Next time when you SSH login, you’ll not see the message again.&lt;/p&gt;

&lt;p&gt;If you prefer not to input the SSH key file location and the username everytime you use the ssh command, you could setup the SSH config in your user machine as shown below:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;&lt;span class="nb"&gt;cat&lt;/span&gt; ~/.ssh/config

Host host1
   HostName host1.example.com
   User bob
   IdentityFile ~/.ssh/id_rsa
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Description of the fields used in the above config file:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Host&lt;/strong&gt; — the nickname for the host.&lt;br&gt;
&lt;strong&gt;HostName&lt;/strong&gt; — the IP address or domain of the remote server.&lt;br&gt;
&lt;strong&gt;User&lt;/strong&gt; — the username associated with the account in the server.&lt;br&gt;
&lt;strong&gt;IdentityFile&lt;/strong&gt; — the location of your SSH key to be used for login to this host.&lt;br&gt;
If you prefer to use a different private key for each host, then you could setup your config file as shown below:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ cat ~/.ssh/config

Host host1
   HostName host1.example.com
   User bob
   IdentityFile ~/.ssh/id_rsa_host1

Host host2
   HostName host2.example.com
   User bob
   IdentityFile ~/.ssh/id_rsa_host2

Host host3
   HostName host3.example.com
   User bob
   IdentityFile ~/.ssh/id_rsa_host3
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here after you could SSH into any host with a simple command like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ ssh [host-nickname] 
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For example, to login to host1:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ ssh host1 
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Step 4: Disable password based authentication, if required.
&lt;/h2&gt;

&lt;p&gt;Now that you have set up your SSH keys for login, it is the right time to completely disable password based login in your SSH server.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Note: Make sure that all other users of the server also have setup SSH public key based login successfully, before you turn-off the password based SSH login. Because once you disable password based authentication, any user still using password for SSH login wouldn’t be able to do so after this.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Edit the &lt;code&gt;/etc/ssh/sshd_config&lt;/code&gt; file in the server using any editor of your choice, say nano or vim. Change the setting named &lt;code&gt;PasswordAuthentication:&lt;/code&gt; to &lt;code&gt;no&lt;/code&gt; as shown below.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ nano /etc/ssh/sshd_config
…
PasswordAuthentication: no
…
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you see any ‘#’ at the beginning of the line, make sure you delete it. # is used to comment out a configuration. You need to uncomment it to make the configuration effective. Save the change and restart the SSH server daemon using the following command as sudo user:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt; $ sudo systemctl restart sshd 
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Verify sshd server is up and running.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt; $ sudo systemctl status sshd 
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Problems at Scale:
&lt;/h2&gt;

&lt;p&gt;Now that you have set up one user for SSH public key based authentication, you as an admin of your organization, should repeat the same procedure to set up SSH public key based authentication for the remaining users.&lt;/p&gt;

&lt;p&gt;If you have more than one server in your organization(which would most likely be the case), then you need to copy each user’s SSH public key to the authorized_keys file in all the servers. This becomes a M * N problem set.&lt;/p&gt;

&lt;h2&gt;
  
  
  SSH public key setup
&lt;/h2&gt;

&lt;p&gt;It is not possible to do this task manually with a scaled infrastructure. Some sort of a software or automation tool is required to complete the task.&lt;/p&gt;

&lt;p&gt;It is highly recommended that a user doesn’t reuse the same SSH public key to login to all SSH servers. If an unwanted user were to get hold of the private key, the potential attack surface becomes large.&lt;/p&gt;

&lt;p&gt;There are some additional problems &amp;amp; operational challenges associated with using SSH public key based authentication. We discuss this in detail in our next article here: &lt;a href="https://www.bastionxp.com/blog/tightening-ssh-access-using-short-lived-ssh-certificates/"&gt;Tightening SSH access using short-lived SSH certificates&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This article was originally published at: &lt;a href="https://www.bastionxp.com/blog/how-to-configure-and-setup-ssh-public-keys-the-right-way/"&gt;https://www.bastionxp.com/blog/how-to-configure-and-setup-ssh-public-keys-the-right-way/&lt;/a&gt;&lt;/p&gt;

</description>
      <category>ssh</category>
      <category>bastionhost</category>
      <category>sshpublickey</category>
      <category>sshsecureaccess</category>
    </item>
    <item>
      <title>Tighten SSH access using short-lived SSH certificates</title>
      <dc:creator>gvelrajan</dc:creator>
      <pubDate>Thu, 10 Mar 2022 04:14:28 +0000</pubDate>
      <link>https://dev.to/gvelrajan/tighten-ssh-access-using-short-lived-ssh-certificates-1g7</link>
      <guid>https://dev.to/gvelrajan/tighten-ssh-access-using-short-lived-ssh-certificates-1g7</guid>
      <description>&lt;p&gt;&lt;em&gt;SSH access using public private key based authentication has several drawbacks that could potentially compromise your organization’s SSH access security. SSH certificate based authentication addresses most of these security problems while simplifying certificate distribution. &lt;a href="https://www.bastionxp.com"&gt;BastionXP PKI/CA solution&lt;/a&gt; automates and simplifies the SSH certificate management while offering additional security services such as issuing short-lived SSH certificates, SSH session recording, monitoring, logging and tracking functionalities for auditing purposes.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Traditionally, enterprises use SSH public private key based authentication for SSH login to servers - both in-house and in the cloud.&lt;/p&gt;

&lt;p&gt;Usually, IT admins create, copy and set up the SSH public private keys for each host (host key) when the VM or server is brought into service. Similarly, IT admins create, copy and set up the SSH public private keys for each user (user key) who needs to gain access to the VM or server. Sometimes, they even use a homegrown or third party tool to create and distribute SSH public private keys.&lt;/p&gt;

&lt;h2&gt;
  
  
  Problem:
&lt;/h2&gt;

&lt;p&gt;Setting up a SSH public private key requires so much time and effort. The admins need to meticulously create, copy and set up a public private key for each user (and also for each host) without leaving any relic anywhere.&lt;/p&gt;

&lt;p&gt;For example, the user public key needs to be appended to the host machine’s ~/.ssh/authorized-keys file and the user private key needs to be copied to a folder (~/.ssh/) in the user’s device such as laptop or desktop. Note that the user public key needs to be copied to each and every host that the user needs access to.&lt;/p&gt;

&lt;p&gt;As a result, the server and user onboarding process is usually laborious, slow and cumbersome. At scale, the problem only gets magnified and the key distribution become really messy.&lt;/p&gt;

&lt;p&gt;Here are some security issues associated with using SSH public private key based authentication for SSH login:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Copy of an SSH key pair left undeleted in emails or local folders or shared online storages, while copying to the host or the user’s machine.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;SSH keys don’t have an expiry date or validity period stamped in them. So they can be used perpetually. The technology doesn’t force the admins or users to rotate the keys periodically. As a result, there is no real urge to renew SSH keys periodically. Secondly, rekeying and distributing the keys to servers and user machines at scale requires significant planning and execution. This builds up the inertia against rotating the SSH keys periodically.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Some users use the same SSH key pair to login to multiple host machines, potentially increasing the attack surface for any unwanted user who gains access to such an SSH key.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;When users connect to a server for the first time, weird cryptic messages are shown to users to identify the host key fingerprint and accept it, so that the host key is stored permanently in the ‘known_hosts’ file (~/.ssh/known_hosts) for future references. Mostly, users blindly accept the message and continue with the login anyway, without bothering to know the authenticity of the host they are trying to log in. The only way to address this security problem is to pre-populate the “known_hosts” file with the host public keys of all known hosts that the user would potentially login to. In large organizations, this list is huge and changes over time, which means the ‘known_hosts" file on each user’s machine should be kept updated as well. As a result, most IT teams don’t follow this approach.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;SSH keys don’t have the hostname or username stamped in them. As a result, any host that is setup with the SSH key could pretend to be the actual host.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;When users leave the organization, SSH keys assigned to them are usually not deleted from the “authorized_keys” file in all the host machines.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Solution:
&lt;/h2&gt;

&lt;p&gt;The solution to all the above security problems is to use SSH certificates for SSH login and authentication.&lt;/p&gt;

&lt;h2&gt;
  
  
  How SSH Certificate based authentication works:
&lt;/h2&gt;

&lt;p&gt;Each organization sets up a Public Key Infrastructure (PKI) to issue SSH certificates to its hosts and users. Certificate Authority(CA) is the prime component of a PKI. For SSH certificate based authentication, two CAs need to be created - a Host Certification Authority(Host CA) and a User Certification Authority (User CA). Host certificates are signed by the Host CA and the user certificates are signed by the User CA.&lt;/p&gt;

&lt;p&gt;A host certificate and the corresponding private key needs to be stored in the host machine only. Similarly, a user certificate and the corresponding private key needs to be stored in the user machine only. User certificates need not be copied to the host machines and host certificates need not be copied to user machines, unlike the SSH public private key based authentication. Advantages of SSH certificate based authentication over SSH public private key based authentication:&lt;/p&gt;

&lt;p&gt;It is sufficient to copy just the user CA certificate to the host machines and the host CA certificate to the user machines. All the users’ certificates need not be copied to all the host machines and all the host machines' certificates need not be copied to all the user machines.&lt;/p&gt;

&lt;p&gt;SSH certificates have an expiry date and validity period stamped in them. So, all SSH certificates will eventually expire sometime in the future. The need to rotate SSH certificates periodically is built into the technology.&lt;/p&gt;

&lt;p&gt;An organization’s security policy could decide the lifetime of a certificate issued to its hosts and users.&lt;/p&gt;

&lt;p&gt;SSH certificates can be issued to a specific identifiable entity within an organization. So SSH certificates have the host or user name stamped in them to identify who owns the certificate. Role based access control (RBAC) is possible with SSH certificates.&lt;/p&gt;

&lt;p&gt;When a user connects to a server for the first time, no weird cryptic messages will be displayed on the screen to identify the fingerprint and trust the host key. The authenticity of the host the user is trying to connect to will be automatically verified using the Host CA Certificate stored locally in the user’s machine.&lt;/p&gt;

&lt;h2&gt;
  
  
  Drawbacks of SSH certificate based authentication:
&lt;/h2&gt;

&lt;p&gt;Though, SSH certificate based authentication addresses most of the security problems in the SSH public private key based authentication, it still has the following caveats in it when SSH certificates are managed manually or using any home-built tools:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Rotating or renewing certificates takes time and effort to distribute them. Anyone who gets hold of an SSH certificate could login to a host without any issues. &lt;/li&gt;
&lt;li&gt;Short-lived user certificates are highly secure because it reduces the duration of the damage any unwanted user who holds such a user certificate could cause. However, short-lived certificates require more frequent rotations and therefore more effort from the admin teams. &lt;/li&gt;
&lt;li&gt;Long-lived certificates have the same inherent security risk as the SSH public private key based authentication but requires reduced effort from the admin teams.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  BastionXP Bastion Host PKI/CA Solution:
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://www.bastionxp.com"&gt;BastionXP Bastion Host PKI/CA&lt;/a&gt; solution is an Identity Based Infrastructure Access Management solution.  BastionXP has a built-in Public Key Infrastructure (PKI) and Certificate Authority(CA) that uses Single-Sign On (SSO) with Multi-Factor Authentication (MFA) to automatically generate and distribute short-lived user SSH certificates to end user machines. &lt;/p&gt;

&lt;p&gt;User identity is verified using IAM software such as Microsoft Azure Active Directory, AWS IAM or Okta or other IAM solutions.  User roles and groups defined in the IAM will be used to generate SSH certificates for the user.  &lt;/p&gt;

&lt;p&gt;User SSH certificates expire in 8 hours by default and can be configured to suit an organization’s security policy, to any value like 4 weeks or 30 secs or so.&lt;/p&gt;

&lt;p&gt;Once users use the SSH certificate to login to a host, they can continue with that SSH session for any longer even if the certificate expires. But, if they exit from the SSH session and need re-login, the users need to SSO login again using their MFA credentials to generate a new SSH certificate.&lt;/p&gt;

&lt;p&gt;Because user SSH certificates are short-lived, no certificate cleaning or housekeeping is required in the host or user machines, when a user leaves an organization or when teams get dismantled. The user certificate becomes invalid the next day.&lt;/p&gt;

&lt;h2&gt;
  
  
  Components of the BastionXP Solution:
&lt;/h2&gt;

&lt;p&gt;BastionXP solution has three components:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;SSH Bastion Host with PKI/CA&lt;/li&gt;
&lt;li&gt;BastionXP SSH Server,&lt;/li&gt;
&lt;li&gt;BastionXP SSH client/authentication utility&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;Note: BastionXP Bastion Host solution can be configured to work as a pure play solution or work along with OpenSSH server and OpenSSH client software.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--BIJgKpRj--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/6edkkuxwjygegt1hkdqa.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--BIJgKpRj--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/6edkkuxwjygegt1hkdqa.jpg" alt="BastionXP Bastion Host Solution with Identity Based Infrastructure Access Management" width="800" height="541"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The ** BastionXP bastion host** has a builtin auth server which does the PKI/CA functionality. It can also perform SSH proxy or Jump Host functionality to connect to hosts that exist safely behind it, protected from the internet.&lt;/p&gt;

&lt;p&gt;The ** BastionXP SSH server (sshd)** implementation runs on each host server, talks to the auth server in the BastionXP bastion host, downloads a host certificate from the auth server to the host and has the ability to record SSH sessions for auditing and playback purposes.&lt;/p&gt;

&lt;p&gt;The ** BastionXP SSH client** (a.k.a authentication CLI utility) allows users to authenticate using SSO and MFA based authentication mechanism (Okta/MS 365/G-Suite) to download a short-lived SSH certificate from the auth server(CA ) to the user’s laptop or desktop. The BastionXP SSH client also does the regular SSH client functionalities such as SSH sessions with hosts, agent forwarding, connect to target hosts via a proxy jump host etc.&lt;/p&gt;

&lt;p&gt;BastionXP can be used in any brownfield deployments where OpenSSH servers and clients are already in use and is preferred over the BastionXP SSH server and client software. In such a scenario, BastionXP Bastion Host’s SSH proxy (Jump Host) functionality can be disabled and BastionXP would simply run in the PKI/CA only mode.&lt;/p&gt;

&lt;p&gt;BastionXP could be deployed in three different ways. We’ll discuss each one of them in detail below.&lt;/p&gt;

&lt;h3&gt;
  
  
  BastionXP Deployment Option #1 - CA Only Mode
&lt;/h3&gt;

&lt;p&gt;In the CA only mode of deployment, BastionXP Bastion Host will function only as a CA server to manage the SSH certificates. BastionXP Bastion Host’s SSH proxy mode (or Jump Host) functionality will be disabled. An OpenSSH server (already in place) will perform the Jump Host functionality.&lt;/p&gt;

&lt;p&gt;SSH host certificates need to be generated by an admin using a BastionXP provided API executed from the host machines running OpenSSH server. Usually, SSH host certificates have a very long validity period. For example: 4 weeks, 26 weeks, or 52 weeks. This is a configurable value and can be set according to an organization’s security policy.&lt;/p&gt;

&lt;p&gt;Users need to download, install and use a simple CLI tool provided by BastionXP to login into their SSO provider using MFA and download the short-lived user SSH certificates from the BastionXP CA to their laptops or a desktops. Users need to use this CLI tool only once everyday when they begin their work in the morning because the short-lived user certificate will be valid for 8 hours by default (This validity period is a configurable value).&lt;/p&gt;

&lt;h3&gt;
  
  
  BastionXP Deployment Option #2 - SSH Jump Host + CA Mode
&lt;/h3&gt;

&lt;p&gt;In this mode, BastionXP Bastion Host will replace an OpenSSH server functioning as a Bastion Host or Jump Host. BastionXP Bastion Host will function as the SSH proxy server or Jump Host, in addition to performing the CA functionality for SSH certificate management. However, the hosts residing behind the Jump Host will still run the OpenSSH server and the user machines will continue to use the OpenSSH client. BastionXP Bastion Host can interoperate seamlessly with OpenSSH servers running in the host machines and the OpenSSH clients running the user machines.&lt;/p&gt;

&lt;h3&gt;
  
  
  BastionXP Deployment Option #3 - Pure Play Mode
&lt;/h3&gt;

&lt;p&gt;In the pure play mode, BastionXP software will run everywhere in the network as an SSH server, SSH client and as an SSH Jump Host/CA server. The diagram below explains this mode of operation.&lt;/p&gt;

&lt;p&gt;BastionXP Bastion Host Solution with SSH Certificate Management&lt;/p&gt;

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

&lt;p&gt;SSH public private key based authentication is prone for security breaches as it doesn’t have an expiry date and user or host identity associated with the keys. SSH certificate based authentication addresses several drawbacks of SSH public private key based authentication. BastionXP Bastion Host PKI/CA solution automates and simplifies the SSH certificate management while offering additional security services such as short-lived SSH keys, SSH session recording, monitoring, logging and tracking functionalities for auditing purposes&lt;/p&gt;

&lt;h2&gt;
  
  
  Free Trial
&lt;/h2&gt;

&lt;p&gt;Start your &lt;strong&gt;free trial&lt;/strong&gt; of BastionXP Bastion Host solution &lt;a href="https://www.bastionxp.com/"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;To know more about BastionXP Bastion Host solution and request for a demo, please contact us at: &lt;a href="mailto:support@bastionxp.com"&gt;support@bastionxp.com&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;This article was originally published at:  &lt;a href="https://www.bastionxp.com/blog/tightening-ssh-access-using-short-lived-ssh-certificates/"&gt;https://www.bastionxp.com/blog/tightening-ssh-access-using-short-lived-ssh-certificates/&lt;/a&gt;&lt;/p&gt;

</description>
      <category>ssh</category>
      <category>bastionhost</category>
      <category>sshcertificate</category>
      <category>sshpublickey</category>
    </item>
    <item>
      <title>How to develop and test a local microservice with remote microservices</title>
      <dc:creator>gvelrajan</dc:creator>
      <pubDate>Fri, 08 Jan 2021 14:10:47 +0000</pubDate>
      <link>https://dev.to/gvelrajan/develop-and-test-your-microservices-locally-without-toasting-your-laptop-10aa</link>
      <guid>https://dev.to/gvelrajan/develop-and-test-your-microservices-locally-without-toasting-your-laptop-10aa</guid>
      <description>&lt;p&gt;In this article, we'll discuss how to develop, debug, and test a microservice locally on your laptop, without having to run all the other microservices of an app also on your laptop.&lt;/p&gt;

&lt;p&gt;The solution presented in this article could also be used to debug, fix, and test a problem reported by your customer in your live production cluster by routing accesses to your microservice (that has the bug) to the one running in your laptop with the fix.&lt;/p&gt;

&lt;h2&gt;
  
  
  Problem Statement:
&lt;/h2&gt;

&lt;p&gt;Let's say your team is focussed on developing and testing a front-end ReactJS microservice for your company's application that has like 25 other microservices such as Spring Boot, Elastic Search, Redis, Postgres, Grafana, and so on, in it.&lt;/p&gt;

&lt;p&gt;As a dev, you would usually try to run all of these microservices in your laptop so that you could develop,build and test changes to your front-end ReactJS App natively on your laptop.  But running all these 25 microservices on your laptop will make it into a toaster, because you are pushing your laptop cpu, memory and power consumption to their maximum capacity throughout the day.   &lt;/p&gt;

&lt;h2&gt;
  
  
  Workarounds Used Today
&lt;/h2&gt;

&lt;p&gt;Many try to workaround this problem by upgrade their RAM or disk or fan module or even the laptop itself.  &lt;/p&gt;

&lt;p&gt;This adds more costs to your organization. Sometimes it may make you wonder, "Was it really a smart decision to convert your monolithic applications into microservices, in the first place?"  &lt;/p&gt;

&lt;p&gt;Don't worry, you are not left alone.  Many companies that have begin their journey into the microservices world, for the benefits it offers, have faced the exact same problem. And, fortunately, &lt;a href="https://www.socketxp.com"&gt;SocketXP&lt;/a&gt; has a solution to address this problem.&lt;/p&gt;

&lt;h2&gt;
  
  
  Wall Power Sockets Analogy
&lt;/h2&gt;

&lt;p&gt;Let me ask you this question. Would you run a huge nuclear power reactor in your house just because you needed some electricity to run your TV, Air Conditioner and Washing machine? The answer would be "no". You'd just install a couple of sockets on your wall, run a power cable to the energy company in your city and hook up your electrical equipments to those wall sockets. Neat and simple isn't it?&lt;/p&gt;

&lt;p&gt;Then why do we try to run all our microservices(both 800 pound gorillas and tiny little mice ones) on that poor little laptop on your lap, all day long, just because you need to focus on developing and testing one front-end microservice?  You could very well install software "wall sockets" on your laptop and have your ReactJS front-end microservice talk to 25 other microservices running remotely in a cloud (or some on-prem cluster perhaps?) via the software "wall sockets" And vice-versa.&lt;/p&gt;

&lt;p&gt;Our SocketXP Microservice Remote Access solution would help create those software "wall-sockets" in your laptop, for all your remote microservices.&lt;/p&gt;

&lt;h2&gt;
  
  
  How SocketXP Microservice Remote Access Solution Works?
&lt;/h2&gt;

&lt;p&gt;You need to download and run a SocketXP proxy agent (also available as Docker Container) on your laptop and on your remote cluster where other N-1 microservices of your application reside.&lt;/p&gt;

&lt;p&gt;SocketXP proxy agent will create "tcp or http" sockets on your laptop (one for each of the microservice running in a remote cluster) and run a bidirectional TLS tunnel between your laptop and your remote cluster.  We'd also adjust DNS records (for those remotely running microservices) in your laptop to route to the localhost IP address.  So that, any requests from your front-end microservices to these 25 other microservices, would be routed to these local sockets.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Your front-end microservice would continue to connect to other microservices of the app as usual, without requiring any modifications to your code or configurations.&lt;/strong&gt;*&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Docker Container Demo
&lt;/h2&gt;

&lt;p&gt;For this exercise, we are going to run Postgres DB as a Docker Container in a remote server and make a python based backend microservice (under development in my laptop) access the remote DB via the SocketXP proxy. &lt;/p&gt;

&lt;p&gt;Postgres DB is accessible via the hostname &lt;code&gt;postgres&lt;/code&gt; and port &lt;code&gt;5432&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Here is the simple backend microservice written in python.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="err"&gt;$&lt;/span&gt;&lt;span class="n"&gt;cat&lt;/span&gt; &lt;span class="n"&gt;backend&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;py&lt;/span&gt; 
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;psycopg2&lt;/span&gt;

&lt;span class="n"&gt;con&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;psycopg2&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;connect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;database&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"postgres"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"gvelrajan"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;password&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"pa$$word123"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;host&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"postgres"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;port&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"5432"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Database opened successfully"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;cur&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;con&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;cursor&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="n"&gt;cur&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;execute&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;'''CREATE TABLE STUDENT
      (ADMISSION INT PRIMARY KEY     NOT NULL,
      NAME           TEXT    NOT NULL,
      AGE            INT     NOT NULL,
      COURSE        CHAR(50),
      DEPARTMENT        CHAR(50));'''&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Table created successfully"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;cur&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;execute&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"INSERT INTO STUDENT (ADMISSION,NAME,AGE,COURSE,DEPARTMENT) VALUES (34231, 'Dave', 19, 'Information Technology', 'ICT')"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="n"&gt;cur&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;execute&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"INSERT INTO STUDENT (ADMISSION,NAME,AGE,COURSE,DEPARTMENT) VALUES (34232, 'Gary', 18, 'Electrical Engineering', 'ICT')"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="n"&gt;cur&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;execute&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"INSERT INTO STUDENT (ADMISSION,NAME,AGE,COURSE,DEPARTMENT) VALUES (34233, 'Abel', 17, 'Computer Science', 'ICT')"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="k"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Student records added to the table successfully"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;con&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;commit&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="n"&gt;con&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;close&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The python backend microservice connects to the DB using the hostname 'postgres' and port '5432'&lt;/p&gt;

&lt;h3&gt;
  
  
  Run the Postgres DB Docker Container
&lt;/h3&gt;

&lt;p&gt;First create a docker volume&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;docker volume create postgres
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Next run the Postgres DB container and mount the &lt;code&gt;postgres&lt;/code&gt; volume in the host machine to the directory &lt;code&gt;/var/lib/postgresql/data&lt;/code&gt; inside the container.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;docker run &lt;span class="nt"&gt;--name&lt;/span&gt; postgres &lt;span class="nt"&gt;--restart&lt;/span&gt; unless-stopped &lt;span class="nt"&gt;--net&lt;/span&gt; appnet &lt;span class="nt"&gt;--mount&lt;/span&gt; &lt;span class="nb"&gt;source&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;postgres,target&lt;span class="o"&gt;=&lt;/span&gt;/var/lib/postgresql/data &lt;span class="nt"&gt;-e&lt;/span&gt; &lt;span class="nv"&gt;POSTGRES_USER&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;gvelrajan &lt;span class="nt"&gt;-e&lt;/span&gt; &lt;span class="nv"&gt;POSTGRES_PASSWORD&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;pa&lt;span class="nv"&gt;$$&lt;/span&gt;word123 &lt;span class="nt"&gt;-e&lt;/span&gt; &lt;span class="nv"&gt;POSTGRES_DB&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;postgres &lt;span class="nt"&gt;-d&lt;/span&gt; postgres:latest
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Run SocketXP Proxy Agent container in a Cluster/Server
&lt;/h3&gt;

&lt;p&gt;First go to &lt;a href="https://portal.socketxp.com"&gt;SocketXP Portal&lt;/a&gt;. Signup for a free account and get your authtoken there.&lt;/p&gt;

&lt;p&gt;Use your authtoken in the below config file.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="err"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;cat&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;config.json&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"authtoken"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"&amp;lt;your-auth-token-goes-here&amp;gt;"&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"tunnel_enabled"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; 
    &lt;/span&gt;&lt;span class="nl"&gt;"tunnels"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[{&lt;/span&gt;&lt;span class="w"&gt; 
        &lt;/span&gt;&lt;span class="nl"&gt;"destination"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"tcp://postgres:5432"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; 
        &lt;/span&gt;&lt;span class="nl"&gt;"iot_device_id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"postgres-mservice-cluster1"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; 
    &lt;/span&gt;&lt;span class="p"&gt;}]&lt;/span&gt;&lt;span class="w"&gt; 
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Store the config.json file in a local directory(/home/gvelrajan/config/config.json) and map the directory into the SocketXP docker container at /data as shown in the command below to start the docker container.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker run &lt;span class="nt"&gt;--name&lt;/span&gt; socketxp &lt;span class="nt"&gt;--restart&lt;/span&gt; unless-stopped &lt;span class="nt"&gt;--net&lt;/span&gt; appnet &lt;span class="nt"&gt;-d&lt;/span&gt;  &lt;span class="nt"&gt;-v&lt;/span&gt; /home/gvelrajan/config:/data expresssocket/socketxp:latest
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Execute the following command to check the logs for success status or any errors:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker logs socketxp
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It would have something like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;Connected.
TCP tunnel &lt;span class="o"&gt;[&lt;/span&gt;gvelrajan-5bz4y6hi] created.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now go to the SocketXP Portal's &lt;a href="https://portal.socketxp.com/#/tunnels"&gt;Tunnel Page&lt;/a&gt;.  Check the name of the tunnel created and its status.&lt;/p&gt;

&lt;h3&gt;
  
  
  Run SocketXP Proxy Agent on your Laptop
&lt;/h3&gt;

&lt;p&gt;First download the SocketXP Proxy Agent in your laptop from the &lt;a href="https://www.socketxp.com/download"&gt;SocketXP download page&lt;/a&gt;.  SocketXP Proxy Agent is available for all OS versions - Windows/Mac/Linux.&lt;/p&gt;

&lt;p&gt;Use the same SocketXP authtoken you used in the previous section to authenticate the proxy agent with SocketXP Cloud Gateway.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="err"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;cat&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;config.json&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"authtoken"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"&amp;lt;your-auth-token-goes-here&amp;gt;"&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"tunnel_enabled"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; 
    &lt;/span&gt;&lt;span class="nl"&gt;"tunnels"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[{&lt;/span&gt;&lt;span class="w"&gt; 
        &lt;/span&gt;&lt;span class="nl"&gt;"destination"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"tcp://postgres:5432"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; 
        &lt;/span&gt;&lt;span class="nl"&gt;"iot_device_id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"postgres-mservice-cluster1"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"iot_slave"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}]&lt;/span&gt;&lt;span class="w"&gt; 
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;socketxp &lt;span class="nt"&gt;--config&lt;/span&gt; config.json
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The above config requests socketxp agent to run in slave mode and create a local proxy TCP socket in your laptop at &lt;code&gt;127.0.0.1:5432&lt;/code&gt;. Also it requests socketxp agent to create a secure TLS connection to the &lt;code&gt;postgres-mservice-cluster1&lt;/code&gt; proxy device (running in your remote cluster or server) we created in the previous section.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt;&lt;br&gt;
Although it is called TCP socket, we run TLS on top of it.  So your data is securely transmitted over the internet end-to-end.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Next, update the DNS record in your laptop with the following command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"127.0.0.1    postgres"&lt;/span&gt; | &lt;span class="nb"&gt;sudo tee&lt;/span&gt; &lt;span class="nt"&gt;-a&lt;/span&gt; /etc/hosts &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; /dev/null
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We need to add the above hostname mapping for our &lt;code&gt;postgres&lt;/code&gt; microservice so that any local requests to the microservice will be routed to our SocketXP proxy agent listening at IP &lt;code&gt;127.0.0.1&lt;/code&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Run the python backend microserver
&lt;/h3&gt;

&lt;p&gt;We are all set to run the python backend microservice under development in our laptop.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;python backend.py
Database opened successfully
Table created successfully
Student records added to the table successfully
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Let's validate this success by running an SQL query in our remote postgres database.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="err"&gt;$&lt;/span&gt; &lt;span class="n"&gt;docker&lt;/span&gt; &lt;span class="k"&gt;exec&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;it&lt;/span&gt; &lt;span class="n"&gt;postgres&lt;/span&gt; &lt;span class="n"&gt;psql&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;U&lt;/span&gt; &lt;span class="n"&gt;gvelrajan&lt;/span&gt; &lt;span class="n"&gt;postgres&lt;/span&gt;
&lt;span class="n"&gt;postgres&lt;/span&gt;&lt;span class="o"&gt;=#&lt;/span&gt; &lt;span class="err"&gt;\&lt;/span&gt;&lt;span class="k"&gt;c&lt;/span&gt; &lt;span class="n"&gt;postgres&lt;/span&gt;
&lt;span class="n"&gt;postgres&lt;/span&gt;&lt;span class="o"&gt;=#&lt;/span&gt; &lt;span class="err"&gt;\&lt;/span&gt;&lt;span class="n"&gt;d&lt;/span&gt;
          &lt;span class="n"&gt;List&lt;/span&gt; &lt;span class="k"&gt;of&lt;/span&gt; &lt;span class="n"&gt;relations&lt;/span&gt;
 &lt;span class="k"&gt;Schema&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt;  &lt;span class="n"&gt;Name&lt;/span&gt;   &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="k"&gt;Type&lt;/span&gt;  &lt;span class="o"&gt;|&lt;/span&gt;   &lt;span class="k"&gt;Owner&lt;/span&gt;   
&lt;span class="c1"&gt;--------+---------+-------+-----------&lt;/span&gt;
 &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="n"&gt;student&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="k"&gt;table&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="n"&gt;gannygans&lt;/span&gt;
&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="k"&gt;row&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;postgres&lt;/span&gt;&lt;span class="o"&gt;=#&lt;/span&gt; &lt;span class="k"&gt;select&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="n"&gt;student&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
 &lt;span class="n"&gt;admission&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="n"&gt;age&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt;                       &lt;span class="n"&gt;course&lt;/span&gt;                       &lt;span class="o"&gt;|&lt;/span&gt;                     &lt;span class="n"&gt;department&lt;/span&gt;                     
&lt;span class="c1"&gt;-----------+------+-----+----------------------------------------------------+----------------------------------------------------&lt;/span&gt;
     &lt;span class="mi"&gt;34231&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="n"&gt;Dave&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt;  &lt;span class="mi"&gt;19&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="n"&gt;Information&lt;/span&gt; &lt;span class="n"&gt;Technology&lt;/span&gt;                             &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="n"&gt;ICT&lt;/span&gt;                                               
     &lt;span class="mi"&gt;34232&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="n"&gt;Gary&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt;  &lt;span class="mi"&gt;18&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="n"&gt;Electrical&lt;/span&gt; &lt;span class="n"&gt;Engineering&lt;/span&gt;                             &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="n"&gt;ICT&lt;/span&gt;                                               
     &lt;span class="mi"&gt;34233&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="n"&gt;Abel&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt;  &lt;span class="mi"&gt;17&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="n"&gt;Computer&lt;/span&gt; &lt;span class="n"&gt;Science&lt;/span&gt;                                   &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="n"&gt;ICT&lt;/span&gt;                                               
&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt; &lt;span class="k"&gt;rows&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;END&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Awesome! We are able to develop/test our local python backend service and make it to seamlessly connect with the remote &lt;code&gt;postgres&lt;/code&gt; DB microservice.&lt;/p&gt;

&lt;h2&gt;
  
  
  Make a remote NGINX microservice locally accessible
&lt;/h2&gt;

&lt;p&gt;Now suppose, in addition to the postgres db microservice, we also need to make an NGINX microserice locally accessible from our laptop, use the following &lt;code&gt;config.json&lt;/code&gt; file to setup the SocketXP Proxy Agent in the remote server/cluster.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="err"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;cat&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;config.json&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"authtoken"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"&amp;lt;your-auth-token-goes-here&amp;gt;"&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"tunnel_enabled"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; 
    &lt;/span&gt;&lt;span class="nl"&gt;"tunnels"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; 
        &lt;/span&gt;&lt;span class="nl"&gt;"destination"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"tcp://postgres:5432"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; 
        &lt;/span&gt;&lt;span class="nl"&gt;"iot_device_id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"postgres-mservice-cluster1"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; 
      &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; 
        &lt;/span&gt;&lt;span class="nl"&gt;"destination"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"tcp://nginx:80"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; 
        &lt;/span&gt;&lt;span class="nl"&gt;"iot_device_id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"nginx-mservice-cluster1"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; 
      &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; 
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Next, go to your laptop, and update the config.json file to create a local Proxy for the nginx microservice, as shown below.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="err"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;cat&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;config.json&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"authtoken"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"&amp;lt;your-auth-token-goes-here&amp;gt;"&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"tunnel_enabled"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; 
    &lt;/span&gt;&lt;span class="nl"&gt;"tunnels"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; 
        &lt;/span&gt;&lt;span class="nl"&gt;"destination"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"tcp://postgres:5432"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; 
        &lt;/span&gt;&lt;span class="nl"&gt;"iot_device_id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"postgres-mservice-cluster1"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"iot_slave"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="w"&gt; 
      &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; 
        &lt;/span&gt;&lt;span class="nl"&gt;"destination"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"tcp://nginx:80"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; 
        &lt;/span&gt;&lt;span class="nl"&gt;"iot_device_id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"nginx-mservice-cluster1"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; 
        &lt;/span&gt;&lt;span class="nl"&gt;"iot_slave"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="w"&gt; 
      &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; 
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;socketxp &lt;span class="nt"&gt;--config&lt;/span&gt; config.json
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The above config will create a TCP listening socket at port 80 in your laptop.  Make sure port 80 is free in your laptop and not used by any other application.&lt;/p&gt;

&lt;p&gt;Next, add the follow DNS entry into your &lt;code&gt;/etc/hosts&lt;/code&gt; file, so that any local DNS resolution requests to access your &lt;code&gt;ngnix&lt;/code&gt; service will be routed to the SocketXP Proxy Agent listening on IP 127.0.0.1.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"127.0.0.1    nginx"&lt;/span&gt; | &lt;span class="nb"&gt;sudo tee&lt;/span&gt; &lt;span class="nt"&gt;-a&lt;/span&gt; /etc/hosts &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; /dev/null
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now open up a browser in your laptop and point it to: &lt;a href="http://nginx:80"&gt;http://nginx:80&lt;/a&gt; or simply &lt;a href="http://nginx"&gt;http://nginx&lt;/a&gt;.  It will open up the NNGINX home page as shown below.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--IjVSP6uR--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/i/naop7dmmxxkordq6uqdh.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--IjVSP6uR--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/i/naop7dmmxxkordq6uqdh.png" alt="socketxp microservice remote access" width="800" height="452"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;We are looking for beta customers to evaluate our SocketXP Microservice Remote Access Solution.  Please write to us at: &lt;a href="//support@socketxp.com"&gt;support@socketxp.com&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;strong&gt;This article was originally published at: &lt;a href="https://www.socketxp.com/blog"&gt;https://www.socketxp.com/blog&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;

</description>
    </item>
    <item>
      <title>How to SSH into a Kubernetes Worker Node</title>
      <dc:creator>gvelrajan</dc:creator>
      <pubDate>Thu, 31 Dec 2020 07:29:25 +0000</pubDate>
      <link>https://dev.to/gvelrajan/how-to-ssh-into-a-kubernetes-worker-node-2mm3</link>
      <guid>https://dev.to/gvelrajan/how-to-ssh-into-a-kubernetes-worker-node-2mm3</guid>
      <description>&lt;p&gt;Kubernetes is a very popular and widely deployed container management and orchestration platform, preferred by devops engineers worldwide today.&lt;/p&gt;

&lt;p&gt;Usually Kubernetes clusters and their worker nodes are not exposed to the public Internet but the apps running in them are.&lt;/p&gt;

&lt;p&gt;In this article, I’ll discuss how to configure SocketXP lightweight VPN solution to remote SSH access your private Kubernetes cluster worker nodes in your on-prem cloud or private cloud or public cloud (AWS, MS Azure, GCP, Digital Ocean etc.) or multi-cloud.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; We at SocketXP are looking for beta customers to evaluate and provide feedback for our Kubernetes Remote Access Solution.  Please feel free to reach out to us at: &lt;a href="mailto:support@socketxp.com"&gt;support@socketxp.com&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Prerequisites:
&lt;/h2&gt;

&lt;p&gt;You are expected to have a working Kubernetes Cluster with atleast one worker node in it. And you could reach those worker nodes now.&lt;/p&gt;

&lt;h2&gt;
  
  
  Overall Strategy -- In a nutshell
&lt;/h2&gt;

&lt;p&gt;We'll install SocketXP agent in your worker nodes and configure it to function as an SSH server.  SocketXP agent will also establish a secure TLS VPN connection with the SocketXP Cloud Gateway.  You could then, remote SSH into your Kubernetes worker nodes from the SocketXP Cloud Gateway Portal using your browser.  No SSH client is required to SSH into your worker nodes.&lt;/p&gt;

&lt;p&gt;Excited? Let's get started!&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 1:  Download and Install
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://www.socketxp.com/download/" rel="noopener noreferrer"&gt;Download and install&lt;/a&gt; the SocketXP agent on your Kubernetes Worker Node.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 2: Get your Authentication Token
&lt;/h3&gt;

&lt;p&gt;Sign up at &lt;a href="https://portal.socketxp.com" rel="noopener noreferrer"&gt;https://portal.socketxp.com&lt;/a&gt; and get your authentication token.&lt;/p&gt;

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

&lt;p&gt;Use the following command to authenticate you node with the SocketXP Cloud Gateway using the auth token.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
 bash
$ socketxp login &amp;lt;your-auth-token-goes-here&amp;gt;


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

&lt;/div&gt;
&lt;h3&gt;
  
  
  Step 3: Create SocketXP TLS VPN Tunnel for Remote SSH Access
&lt;/h3&gt;

&lt;p&gt;Use the following command to create a secure and private TLS tunnel VPN connection to the SocketXP Cloud Gateway.&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
 bash
$ socketxp connect tcp://localhost:22  --iot-device-id "kube-worker-node-001"  --enable-ssh --ssh-username "test-user" --ssh-password "password123"

TCP tunnel [test-user-gmail-com-34445] created.
Access the tunnel using SocketXP agent in IoT Slave Mode


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

&lt;/div&gt;

&lt;p&gt;Where TCP port 22 is the default port at which the SocketXP agent would listen for SSH connections from any SSH clients.  The "--iot-device-id" represents a unique identifier assigned to the Kubernetes worker node within your organization.  It could be any string value but it must be unique for each of your worker node.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Security Info:&lt;/strong&gt;&lt;br&gt;
SocketXP &lt;strong&gt;does not&lt;/strong&gt; create any public TCP tunnel endpoints that can be connected and accessed by anyone in the internet using an SSH client. SocketXP TCP tunnel endpoints are not exposed to the internet and can be accessed only using the SocketXP agent (using the auth token of the user) or through the XTERM terminal in the SocketXP Portal page.&lt;/p&gt;

&lt;p&gt;SocketXP also has the option to setup and use your private/public keys to remote SSH into your worker nodes.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;You could now remote SSH into your Kubernetes worker node by clicking the terminal icon as shown in the screenshot below. &lt;/p&gt;

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

&lt;p&gt;Next, you'll will be prompted to provide your SSH login and password.&lt;/p&gt;

&lt;p&gt;Once your credentials are authenticated with your SSH server you'll be logged into your device's shell prompt.&lt;/p&gt;

&lt;p&gt;The screen capture below shows the "htop" shell command output from an SSH session created using the XTERM window in the SocketXP Portal page.&lt;/p&gt;

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

&lt;h2&gt;
  
  
  Configuring SocketXP agent to run in slave mode
&lt;/h2&gt;

&lt;p&gt;This is an alternate method for SSH into your private worker node from a remote location using the SocketXP Remote SSH Access solution.&lt;/p&gt;

&lt;p&gt;If you don't want to access your IoT  device or RPi from the browser(SocketXP Portal) and you want to access it using an SSH client (such as PuTTy) installed on your laptop or desktop, follow the instructions below.&lt;/p&gt;

&lt;p&gt;First download and install the regular SocketXP agent software on your accessing device (such as a laptop running Windows or Mac OS). Next, configure the agent to run in slave mode using the command option "--iot-slave" as shown in the example below. Also, specify the name of the private TCP tunnel you want to connect to, using the  &lt;code&gt;--tunnel-name&lt;/code&gt; option.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
 bash
$ socketxp connect tcp://localhost:3000 --iot-slave --tunnel-name test-user-gmail-com-34445

Listening for TCP connections at:
Local URL -&amp;gt; tcp://localhost:3000
Accessing the IoT device from your laptop


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

&lt;/div&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Why this is important?:&lt;/strong&gt;&lt;br&gt;
SocketXP IoT Agent when run in Slave Mode acts like a localproxy server.  It proxies all connections to a user-specified local port (10111 in the example above) in your laptop/PC to the SocketXP Cloud Gateway using a secure SSL/TLS tunnel.  Also the SocketXP Agent authenticates itself with the SocketXP Cloud Gateway using your auth token.  This ensures that only legitimate, authenticated users are permitted to access your private worker nodes. SocketXP ensures Zero-Trust security on all connected devices.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Now you can SSH access your Kubernetes Worker Node using the above SocketXP local endpoint, as shown below.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
 bash
$ ssh -i ~/.ssh/test-user-private.key test-user@localhost -p 3000


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

&lt;/div&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Tip:&lt;/strong&gt;&lt;br&gt;
You can also use &lt;a href="https://www.putty.org/" rel="noopener noreferrer"&gt;PuTTY&lt;/a&gt; SSH client to remote SSH into your device using the same parameters show above.  Similarly, you can use PuTTY or &lt;a href="https://filezilla-project.org/" rel="noopener noreferrer"&gt;FileZilla&lt;/a&gt; to perform SFTP actions such as file upload and file download to your private Kubernetes Worker Nodes.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; We at SocketXP are looking for beta customers to evaluate and provide feedback for our Kubernetes Remote Access Solution that includes Worker Node/Pod SSH access/Microservice Remote Access/Database Remote access.  Please feel free to connect with us at: &lt;a href="mailto:support@socketxp.com"&gt;support@socketxp.com&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;strong&gt;This article was originally published at: &lt;a href="https://www.socketxp.com/blog" rel="noopener noreferrer"&gt;https://www.socketxp.com/blog&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Remote Access Kubernetes Dashboard</title>
      <dc:creator>gvelrajan</dc:creator>
      <pubDate>Fri, 04 Dec 2020 16:59:45 +0000</pubDate>
      <link>https://dev.to/gvelrajan/remote-access-kubernetes-dashbboard-phc</link>
      <guid>https://dev.to/gvelrajan/remote-access-kubernetes-dashbboard-phc</guid>
      <description>&lt;p&gt;Kubernetes is a popular cluster and container management/orchestration platform widely used in pulic and private clouds. Kubernetes Dashboard is a web-based Kubernetes user interface. You can use Dashboard to deploy containerized applications to a Kubernetes cluster, troubleshoot your containerized application, and manage the cluster resources.&lt;/p&gt;

&lt;h2&gt;
  
  
  SocketXP TLS VPN
&lt;/h2&gt;

&lt;p&gt;SocketXP TLS VPN solution (a lightweight VPN) provides secure remote access to private Kubernetes Clusters in your private cloud or public cloud. SocketXP also provides a secure public URL to access your local private applications including Kubernetes Dashboard.&lt;/p&gt;

&lt;p&gt;SocketXP agent is available as a docker container in the &lt;a href="https://hub.docker.com/r/expresssocket/socketxp" rel="noopener noreferrer"&gt;SocketXP DockerHub Repository&lt;/a&gt;. Run the SocketXP Docker container as a standalone container (as explained in the below sections) in your Kubernetes cluster to setup remote access to your Kubernetes Dashboard.&lt;/p&gt;

&lt;h2&gt;
  
  
  Deploying the Dashboard UI:
&lt;/h2&gt;

&lt;p&gt;Follow the instructions in the &lt;a href="https://kubernetes.io/docs/tasks/access-application-cluster/web-ui-dashboard/" rel="noopener noreferrer"&gt;Kubernetes Open Source Project page&lt;/a&gt;on how to deploy and setup the Dashboard UI in your Kubernetes Cluster.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://kubernetes.io/docs/tasks/access-application-cluster/web-ui-dashboard/" rel="noopener noreferrer"&gt;https://kubernetes.io/docs/tasks/access-application-cluster/web-ui-dashboard/&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;As explained in the Kubernetes official documentation, you need to run the kubectl CLI utility in proxy mode to access your dashboard in a web browser.&lt;/p&gt;

&lt;h2&gt;
  
  
  Kubernetes Dashboard Login from Outside Network
&lt;/h2&gt;

&lt;p&gt;What is the approach to access Kubernetes Dashboard login from outside network?&lt;/p&gt;

&lt;h3&gt;
  
  
  Overall Strategy
&lt;/h3&gt;

&lt;p&gt;Here is the overall strategy to setup remote access to your Kubernetes Dashboard:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Deploy SocketXP VPN agent Docker container in your K8 cluster.&lt;/li&gt;
&lt;li&gt;Install the kubectl CLI utility locally on your laptop.&lt;/li&gt;
&lt;li&gt;Setup the kubectl config file in your laptop with SocketXP Public URL, K8 SSL Certs, and Key.&lt;/li&gt;
&lt;li&gt;Remote access your private Kubernetes cluster from your laptop using the kubectl CLI utility.&lt;/li&gt;
&lt;li&gt;Run kubectl in proxy mode in your laptop.&lt;/li&gt;
&lt;li&gt;Access your Kubernetes dashboard in a web browser via the local kubectl proxy.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  SocketXP Agent Docker Container Deployment:
&lt;/h2&gt;

&lt;p&gt;First go to &lt;a href="https://portal.socketxp.com" rel="noopener noreferrer"&gt;SocketXP Portal&lt;/a&gt;. Signup for a free account and get your authtoken there. Use the authtoken to create a Kubernetes secret as shown below.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;kubectl create secret generic socketxp-credentials --from-literal=authtoken=[your-auth-token-goes-here]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Verify that the secret socketxp-credentials got created.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ kubectl get secrets
NAME                   TYPE                                  DATA   AGE
default-token-5skb7    kubernetes.io/service-account-token   3      4h
socketxp-credentials   Opaque                                1      4h
$
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We'll use the below config.json file to configure the SocketXP agent Docker container. In this example, we are trying to create a secure public web URL and a TLS VPN tunnel to the Kubernetes API server.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="err"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;cat&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;config.json&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; 
    &lt;/span&gt;&lt;span class="nl"&gt;"tunnel_enabled"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; 
    &lt;/span&gt;&lt;span class="nl"&gt;"tunnels"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[{&lt;/span&gt;&lt;span class="w"&gt; 
        &lt;/span&gt;&lt;span class="nl"&gt;"destination"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"https://kubernetes.default"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; 
        &lt;/span&gt;&lt;span class="nl"&gt;"protocol"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"tls"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; 
        &lt;/span&gt;&lt;span class="nl"&gt;"custom_domain"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;""&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; 
        &lt;/span&gt;&lt;span class="nl"&gt;"subdomain"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;""&lt;/span&gt;&lt;span class="w"&gt; 
    &lt;/span&gt;&lt;span class="p"&gt;}],&lt;/span&gt;&lt;span class="w"&gt; 
    &lt;/span&gt;&lt;span class="nl"&gt;"relay_enabled"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; 
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Next create a Kubernetes configmap to store the above SocketXP agent configuration file.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;kubectl create configmap socketxp-configmap --from-file=/home/test-user/config.json
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Verify that the socketxp-configmap got created.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ kubectl describe configmaps socketxp-configmap
Name:         socketxp-configmap
Namespace:    default
Labels:       &amp;lt;none&amp;gt;
Annotations:  &amp;lt;none&amp;gt;

Data
====
config.json:
----
{ "tunnel_enabled": true, "tunnels" : [{ "destination": "https://kubernetes.default", "protocol": "tls", "custom_domain": "", "subdomain": "" }], "relay_enabled": false }

Events:  &amp;lt;none&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now that we have created the authtoken secret and the configmap needed by the SocketXP agent, it's time to launch the SocketXP Docker container expresssocket/socketxp:latest as a Kubernetes Deployment.&lt;/p&gt;

&lt;p&gt;Here is the deployment.yaml file we'll use to create a standalone SocketXP agent deployment.&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="s"&gt;$cat deployment.yaml&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;apps/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;Deployment&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;socketxp&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;socketxp&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;replicas&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1&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;matchLabels&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;socketxp&lt;/span&gt;
  &lt;span class="na"&gt;template&lt;/span&gt;&lt;span class="pi"&gt;:&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;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;socketxp&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;containers&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;socketxp&lt;/span&gt;
        &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;expresssocket/socketxp:latest&lt;/span&gt;
        &lt;span class="na"&gt;env&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;AUTHTOKEN&lt;/span&gt;
            &lt;span class="na"&gt;valueFrom&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
              &lt;span class="na"&gt;secretKeyRef&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;socketxp-credentials&lt;/span&gt;
                &lt;span class="na"&gt;key&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;authtoken&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;config-volume&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;/data&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;config-volume&lt;/span&gt;
          &lt;span class="na"&gt;configMap&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
            &lt;span class="c1"&gt;# Provide the name of the ConfigMap containing the files you want&lt;/span&gt;
            &lt;span class="c1"&gt;#to add to the container&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;socketxp-configmap&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt;&lt;br&gt;
We have created a separate volume named config-volume and mounted it under /data directory inside the container, so that the socketxp-configmap will be available as a config.json file under the /data directory in the running container.&lt;/p&gt;

&lt;p&gt;Next, check if the pods are created from the deployment and running.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ kubectl get pods
NAME                        READY   STATUS    RESTARTS   AGE
socketxp-75cb4dd7c9-bhxfp   1/1     Running   0          4s
$
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now you can retrieve the SocketXP Public URL created for your Kubernetes API server from the SocketXP Portal Page at: &lt;a href="https://portal.socketxp.com/#/tunnels" rel="noopener noreferrer"&gt;https://portal.socketxp.com/#/tunnels&lt;/a&gt; (or) from the pod logs as shown below.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ kubectl logs socketxp-75cb4dd7c9-bhxfp
...
...

Login Succeeded.
User [] Email [test-user@gmail.com].

Connected.
Public URL -&amp;gt; https://test-user-fn4mda420.socketxp.com
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can now use the above SocketXP Public URL to access the Kubernetes Cluster's API server remotely using a kubectl utility.&lt;/p&gt;

&lt;h2&gt;
  
  
  Local kubectl installation
&lt;/h2&gt;

&lt;p&gt;Install the kubectl CLI utility locally on your laptop to remote access your Kubernetes cluster. Follow the instructions here to download and install kubectl on your laptop:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://kubernetes.io/docs/tasks/tools/install-kubectl/(opens" rel="noopener noreferrer"&gt;https://kubernetes.io/docs/tasks/tools/install-kubectl/(opens&lt;/a&gt; new window)&lt;/p&gt;

&lt;p&gt;After you have installed the kubectl CLI utility, overwrite the kubectl config file located at $HOME/.kube/config in your laptop with the one from your cluster's master node($HOME/.kube/config).&lt;/p&gt;

&lt;p&gt;Next, update the API server URL in your kubectl config file to use the SocketXP Public URL &lt;a href="https://test-user-fn4mda420.socketxp.com" rel="noopener noreferrer"&gt;https://test-user-fn4mda420.socketxp.com&lt;/a&gt;, as shown below.&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;v1&lt;/span&gt;
&lt;span class="na"&gt;clusters&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
&lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;cluster&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;certificate-authority&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;/Users/test-user/.minikube/ca.crt&lt;/span&gt;
    &lt;span class="na"&gt;server&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;https://test-user-fn4mda420.socketxp.com&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;minikube&lt;/span&gt;
&lt;span class="na"&gt;contexts&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
&lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;context&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;cluster&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;minikube&lt;/span&gt;
    &lt;span class="na"&gt;user&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;minikube&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;minikube&lt;/span&gt;
&lt;span class="nn"&gt;...&lt;/span&gt;
&lt;span class="nn"&gt;...&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Please ensure that you also copy the client certificate, CA certificate and private key files or authtoken from your Kubernetes cluster's master node to your laptop in the appropriate folder as specified in the kubectl config file.&lt;/p&gt;

&lt;p&gt;Verify that the config works fine, using the following command:&lt;br&gt;
&lt;/p&gt;

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

&lt;/div&gt;



&lt;p&gt;Now remote access or remote manage your private Kubernetes Cluster from your laptop by executing any kubectl command locally:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ kubectl get pods
NAME                        READY   STATUS    RESTARTS   AGE
socketxp-75cb4dd7c9-bhxfp   1/1     Running   0          1h
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt;&lt;br&gt;
When you create more than one replica of the SocketXP agent pod using the deployment, each pod would be assigned a unique SocketXP Public URL. This is because each SocketXP agent pod running in the Kubernetes Cluster will fetch a new Public URL from the SocketXP Cloud Gateway.&lt;/p&gt;
&lt;h2&gt;
  
  
  Run kubectl in proxy mode
&lt;/h2&gt;

&lt;p&gt;To remote access your Kubernetes Dashboard, run the kubectl CLI utility in proxy mode in your laptop as shown below:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ kubectl proxy  
Starting to serve on 127.0.0.1:8001
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Let this command continue to run in the foreground.&lt;/p&gt;

&lt;h2&gt;
  
  
  Remote access Kubernetes Dashboard:
&lt;/h2&gt;

&lt;p&gt;Now you can remote access your Kubernetes Dashboard from your laptop using the following local URL via the kubectl proxy. Kubectl will make Dashboard available at:&lt;/p&gt;

&lt;p&gt;&lt;a href="http://localhost:8001/api/v1/namespaces/kubernetes-dashboard/services/https:kubernetes-dashboard:/proxy/" rel="noopener noreferrer"&gt;http://localhost:8001/api/v1/namespaces/kubernetes-dashboard/services/https:kubernetes-dashboard:/proxy/&lt;/a&gt; (opens new window).&lt;/p&gt;

&lt;p&gt;Now you can view or manage your k8 resources.&lt;/p&gt;

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

&lt;p&gt;Note:  This article was originally published at: &lt;a href="https://www.socketxp.com/iot" rel="noopener noreferrer"&gt;https://www.socketxp.com/iot&lt;/a&gt;&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Configure local kubectl to access remote Kubernetes cluster</title>
      <dc:creator>gvelrajan</dc:creator>
      <pubDate>Wed, 02 Dec 2020 09:40:36 +0000</pubDate>
      <link>https://dev.to/gvelrajan/configure-local-kubectl-to-remote-access-kubernetes-cluster-2g81</link>
      <guid>https://dev.to/gvelrajan/configure-local-kubectl-to-remote-access-kubernetes-cluster-2g81</guid>
      <description>&lt;p&gt;Kubernetes is a very popular and widely deployed container management and orchestration platform, preferred by devops engineers worldwide today. &lt;/p&gt;

&lt;p&gt;Usually Kubernetes clusters are not exposed to the public Internet but the apps running in them are. &lt;/p&gt;

&lt;p&gt;In this article, I’ll discuss how to configure a local kubectl to remote access your Kubernetes cluster or minikube running in a server in your lab or private cloud or public cloud (AWS, MS Azure, GCP, Digital Ocean etc.).&lt;/p&gt;

&lt;h2&gt;
  
  
  Prerequisites:
&lt;/h2&gt;

&lt;p&gt;You are expected to have a basic understanding on:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;How to configure and setup a Kubernetes cluster or minikube&lt;/li&gt;
&lt;li&gt;How to run a Docker container as a Kubernetes deployment and service&lt;/li&gt;
&lt;li&gt;What kubectl and kubeadm tools are and how they are used for Kubernetes cluster, pod management and orchestration.&lt;/li&gt;
&lt;li&gt;You have a working Kubernetes Cluster or Minikube setup already. &lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Overall strategy — In a nutshell
&lt;/h2&gt;

&lt;p&gt;The kubectl CLI utility talks to the Kubernetes cluster via the cluster’s API server. As long as we could make the cluster’s API server accessible from your laptop, we could access or manage your remote Kubernetes cluster or minikube through a local kubectl instance installed on your laptop.&lt;/p&gt;

&lt;p&gt;Enabling secure remote access to the cluster’s API server over the public internet is key here. We’ll use SocketXP VPN solution (SSL/TLS tunnels) to provide secure remote access to the cluster’s API server. SocketXP VPN solution has a free plan for beginners.&lt;/p&gt;

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

&lt;h2&gt;
  
  
  Setup a Kubernetes cluster or Minikube
&lt;/h2&gt;

&lt;p&gt;To begin with setup a Kubernetes cluster or Minikube instance on your laptop.  The aim of this article is not to teach you how to setup a Kubernetes cluster or Minikube. So let’s jump straight into our task at hand, that is, configure local kubectl to remote access Kubernetes cluster or minikube.&lt;/p&gt;

&lt;h2&gt;
  
  
  Install, Setup and Configure Kubectl for remote access to Kubernetes cluster
&lt;/h2&gt;

&lt;p&gt;Follow the below instructions to setup and configure kubectl locally on your laptop for remote access to your Kubernetes cluster or minikube.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step #1 — Install and Setup local Kubectl
&lt;/h3&gt;

&lt;p&gt;Install the kubectl CLI utility on your laptop (Mac/Windows/Linux version) from the Kubernetes project’s public repository. Instruction on how to install and setup kubectl are described here in detail.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step #2 — Copy the kubectl config file
&lt;/h3&gt;

&lt;p&gt;Now go to your Kubernetes cluster’s master node or minikube that you have setup in the previous section and copy the kubectl config file from there to your laptop.&lt;/p&gt;

&lt;p&gt;Usually the kubectl config file is stored at: &lt;code&gt;$Home/.kube/config&lt;/code&gt; in the master node of your remote Kubernetes cluster. This is the config file used by the kubectl utility installed in your remote cluster’s master node.&lt;/p&gt;

&lt;p&gt;Note: kubectl is one of the utilities installed in any Kubernetes cluster or minikube during a cluster setup.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
 sh
$ cat ~/.kube/config
apiVersion: v1
clusters:
- cluster:
 certificate-authority: /home/test-user/.minikube/ca.crt
 server: https://192.168.99.100:8443
 name: minikube
contexts:
- context:
 cluster: minikube
 user: minikube
 name: minikube
current-context: minikube
kind: Config
preferences: {}
users:
- name: minikube
 user:
 client-certificate: /home/test-user/.minikube/profiles/minikube/client.crt
 client-key: /home/test-user/.minikube/profiles/minikube/client.key


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

&lt;/div&gt;

&lt;p&gt;The above kubectl config file was captured from a remote server running minikube cluster.&lt;/p&gt;

&lt;p&gt;Copy this kubectl config file to your laptop and replace any existing config file at &lt;code&gt;$HOME/.kube/config&lt;/code&gt; in your laptop.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step #3 — Copy the SSL certificates and private key
&lt;/h3&gt;

&lt;p&gt;Next, you should copy the SSL certificates and private key used by the kubectl utility installed in the master node of your remote Kubernetes cluster, to your local laptop.&lt;/p&gt;

&lt;p&gt;Copy the CA certificate (ca.crt), client certificate (client.crt) and client private key (client.key) files from your remote Kubernetes cluster to your local laptop. &lt;/p&gt;

&lt;p&gt;The location of these files in the master node of your remote cluster is specified in the kubectl config file you copied in Step#2 (look for the bold text fields in the config file above).&lt;/p&gt;

&lt;p&gt;You could download these certificate and key files to any directory in your local laptop, as long as you update their full path in the appropriate fields in your local kubectl config file (again look for the bold text fields in the config file shown above).&lt;/p&gt;

&lt;h3&gt;
  
  
  Step #4 — Install and setup SocketXP agent
&lt;/h3&gt;

&lt;p&gt;For the locally installed kubectl instance to remote access your Kubernetes cluster’s API server running at &lt;code&gt;https://cluster-ip-address:8443&lt;/code&gt;, you need to setup a public we URL for the API server, so that you could access and manage the cluster from anywhere in the internet.&lt;/p&gt;

&lt;p&gt;SocketXP SSL/TLS VPN tunnels provide a secure, private and lightweight communication channel and a public URL to remote connect to your private Kubernetes cluster’s API server over the internet. Moreover, SocketXP VPN solution is free (checkout the &lt;a href="https://www.socketxp.com/pricing" rel="noopener noreferrer"&gt;“Tunnel Free Plan” here&lt;/a&gt;).&lt;/p&gt;

&lt;p&gt;Follow the instructions here to download and install SocketXP agent docker container on your Kubernetes cluster or minikube as a standalone container deployment.&lt;/p&gt;

&lt;h4&gt;
  
  
  Standalone Container Deployment:
&lt;/h4&gt;

&lt;p&gt;First go to &lt;a href="//htts://portal.socketxp.com"&gt;SocketXP Portal&lt;/a&gt;. Signup for a free account and get your authtoken there. Use the authtoken to create a Kubernetes secret as shown below.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
 sh
$ kubectl create secret generic socketxp-credentials --from-literal=authtoken=[your-auth-token-goes-here]


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

&lt;/div&gt;

&lt;p&gt;Verify that the secret socketxp-credentials got created.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
 sh
$ kubectl get secrets
NAME                   TYPE                                  DATA   AGE
default-token-5skb7    kubernetes.io/service-account-token   3      4h
socketxp-credentials   Opaque                                1      4h
$


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

&lt;/div&gt;

&lt;p&gt;We’ll use the below config.json file to configure the SocketXP agent Docker container. In this example, we are trying to create a secure public web URL and a TLS VPN tunnel to the Kubernetes API server.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
 json
$ cat config.json
{ 
    "tunnel_enabled": true, 
    "tunnels" : [{ 
        "destination": "https://kubernetes.default", 
        "protocol": "tls", 
        "custom_domain": "", 
        "subdomain": "" 
    }], 
    "relay_enabled": false, 
}


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

&lt;/div&gt;

&lt;p&gt;Next create a Kubernetes configmap to store the above SocketXP agent configuration file.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
 sh
kubectl create configmap socketxp-configmap --from-file=/home/test-user/config.json


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

&lt;/div&gt;

&lt;p&gt;Verify that the socketxp-configmap got created.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
 sh
$ kubectl describe configmaps socketxp-configmap
Name:         socketxp-configmap
Namespace:    default
Labels:       &amp;lt;none&amp;gt;
Annotations:  &amp;lt;none&amp;gt;
Data
====
config.json:
----
{ "tunnel_enabled": true, "tunnels" : [{ "destination": "https://kubernetes.default", "protocol": "tls", "custom_domain": "", "subdomain": "" }], "relay_enabled": false }
Events:  &amp;lt;none&amp;gt;


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

&lt;/div&gt;

&lt;p&gt;Now that we have created the authtoken secret and the configmap needed by the SocketXP agent, it’s time to launch the SocketXP Docker container expresssocket/socketxp:latest as a Kubernetes Deployment.&lt;/p&gt;

&lt;p&gt;Here is the &lt;code&gt;deployment.yaml&lt;/code&gt; file we'll use to create a standalone SocketXP agent deployment.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
 yaml
$cat deployment.yaml 
apiVersion: apps/v1
kind: Deployment
metadata:
  name: socketxp
  labels:
    app: socketxp
spec:
  replicas: 1
  selector:
    matchLabels:
      app: socketxp
  template:
    metadata:
      labels:
        app: socketxp
    spec:
      containers:
      - name: socketxp
        image: expresssocket/socketxp:latest
        env:
          - name: AUTHTOKEN
            valueFrom:
              secretKeyRef:
                name: socketxp-credentials
                key: authtoken
        volumeMounts:
        - name: config-volume
          mountPath: /data
      volumes:
        - name: config-volume
          configMap:
            # Provide the name of the ConfigMap containing the files you want
            #to add to the container
            name: socketxp-configmap


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

&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt;&lt;br&gt;
We have created a separate volume named &lt;code&gt;config-volume&lt;/code&gt; and mounted it under &lt;code&gt;/data&lt;/code&gt; directory inside the container, so that the &lt;code&gt;socketxp-configmap&lt;/code&gt; will be available as a &lt;code&gt;config.json&lt;/code&gt; file under the /data directory in the running container.&lt;/p&gt;

&lt;p&gt;Next, check if the pods are created from the deployment and running.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
 sh
$ kubectl get pods
NAME                        READY   STATUS    RESTARTS   AGE
socketxp-75cb4dd7c9-bhxfp   1/1     Running   0          4s
$


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

&lt;/div&gt;

&lt;p&gt;Now you can retrieve the SocketXP Public URL created for your Kubernetes API server from the SocketXP Portal Page at: &lt;a href="https://portal.socketxp.com/#/tunnels" rel="noopener noreferrer"&gt;https://portal.socketxp.com/#/tunnels&lt;/a&gt; (opens new window) or from the pod logs as shown below.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
 sh
$ kubectl logs socketxp-75cb4dd7c9-bhxfp
...
...
Login Succeeded.
User [] Email [test-user@gmail.com].
Connected.
Public URL -&amp;gt; https://test-user-fn4mda420.socketxp.com


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

&lt;/div&gt;
&lt;h3&gt;
  
  
  Step #5 — Update the API server URL
&lt;/h3&gt;

&lt;p&gt;You can now use the above SocketXP Public URL to access the Kubernetes Cluster’s API server remotely using a kubectl utility or directly using your custom application.&lt;br&gt;
If you are using a locally installed kubectl utility from your laptop to remotely access the Kubernetes, then update the API server URL in the kubectl config file located at &lt;code&gt;$HOME/.kube/config&lt;/code&gt; to use the SocketXP Public URL &lt;code&gt;https://test-user-fn4mda420.socketxp.com&lt;/code&gt;&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
 yaml
apiVersion: v1
clusters:
- cluster:
    certificate-authority: /Users/test-user/.minikube/ca.crt
    server: https://test-user-fn4mda420.socketxp.com 
  name: minikube
contexts:
- context:
    cluster: minikube
    user: minikube
  name: minikube
...
...


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

&lt;/div&gt;

&lt;p&gt;Please ensure that you also copy the client certificate, CA certificate and private key files from your Kubernetes cluster’s master node to your laptop in the appropriate folder as specified in the kubectl config file.&lt;br&gt;
Verify that the config works fine, using the following command:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
 sh
kubectl config view


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

&lt;/div&gt;
&lt;h3&gt;
  
  
  Step #6 — Access your Kubernetes cluster remotely from your laptop
&lt;/h3&gt;

&lt;p&gt;Next, you could execute any kubectl commands such as ‘kubectl get pod’ or ‘kubectl get service’ from your laptop and the remote API server should respond back with the status of your pods running in your remote Kubernetes cluster or minikube.&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
 sh
$ kubectl get pods
NAME                        READY   STATUS    RESTARTS   AGE
socketxp-75cb4dd7c9-bhxfp   1/1     Running   0          1h


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

&lt;/div&gt;

&lt;p&gt;Hope that was easy and straight forward to setup it up.&lt;/p&gt;

&lt;h2&gt;
  
  
  Advantages of SocketXP SSL/TLS VPN over other VPN solutions:
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;SocketXP SSL/TLS VPN is a L4 VPN (unlike L2 or L3 VPNs such as MACsec or IPsec, respectively). So remote access to only one specific application in a private network is allowed (unlike L2 or L3 VPNs which permit access to an entire private network).&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;SocketXP SSL/TLS VPN tunnels, like any VPN software, supports client authentication via TLS client authentication. So only a client application (kubectl instances in this case) with a valid TLS client certificate could access or talk to the remote server (Kubernetes cluster API server in the example above). No rogue user or app from the internet could access the server application made accessible via a SocketXP public URL.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;SocketXP TLS tunnels are extremely lightweight unlike OpenVPN or other IPsec VPN softwares in the market, but it provides the exact same level of security (using the same SSL encryption technology) provided by OpenVPN or other IPsec VPN softwares. SocketXP uses the same encryption technology (SSL encryption) used by banks, financial institutions and Governments to securely transfer confidential data over the public internet.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;SocketXP assigns you a unique public URL for your server application with random strings in it, that eliminates any guess work for the random Public URL uniquely assigned to you. This adds an additional level of security, in the first place.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;SocketXP TLS VPN solution enables app-to-app communication only and not network-to-network communication. This drastically reduces the scope for any attack surface. The traffic from the internet over the VPN cannot go beyond the private IP:port boundary.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Moreover, SocketXP VPN Cloud Gateway is an online SaaS service that eliminates the need to run any VPN server in your private cloud or the need to run a VPN client software on your access devices such as laptops.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;And it’s free. Can it get any better than this? Checkout the “Tunnel Free Plan” here.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Have a question or comment, leave it below. Alternatively, you could write to us at: &lt;a href="mailto:support@socketxp.com"&gt;support@socketxp.com&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Note: This article was originally published at: &lt;a href="https://www.socketxp.com/blog" rel="noopener noreferrer"&gt;https://www.socketxp.com/blog&lt;/a&gt;&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Autoupdate Kubernetes Deployment on GitHub Webhook</title>
      <dc:creator>gvelrajan</dc:creator>
      <pubDate>Fri, 10 Jul 2020 12:11:39 +0000</pubDate>
      <link>https://dev.to/gvelrajan/autoupdate-kubernetes-deployment-on-github-webhook-3f43</link>
      <guid>https://dev.to/gvelrajan/autoupdate-kubernetes-deployment-on-github-webhook-3f43</guid>
      <description>&lt;p&gt;Last week I discussed &lt;a href="https://www.socketxp.com/webhookrelay/docker-compose-auto-update-github-webhook/"&gt;how to autoupdate a Docker Compose deployment using SocketXP on receiving a GitHub push or release webhook&lt;/a&gt;. This week I'll discuss how to autoupdate a Kubernetes workload or deployment on receiving a GitHub Webhook when a new version of the app is released.&lt;/p&gt;

&lt;h2&gt;Prerequisites&lt;/h2&gt;

&lt;p&gt;For understanding and following the instructions in this demo you need to have a basic understanding and some working knowledge of the following tools.&lt;/p&gt;

&lt;ul&gt;
    &lt;li&gt;GitHub&lt;/li&gt;
    &lt;li&gt;Docker&lt;/li&gt;
    &lt;li&gt;Kubernetes Cluster&lt;/li&gt;
    &lt;li&gt;Helm&lt;/li&gt;
    &lt;li&gt;SocketXP&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;Continuous Deployment Strategy&lt;/h2&gt;

&lt;p&gt;Our goal is to upgrade our demo app in a GitOps fashion, meaning we don't want to upgrade whenever a new checkin happens into our app git repo but when a change or release is created in our Devops template or script git repo.&lt;/p&gt;

&lt;p&gt;In this demo, I'll show you how to create a separate git repo for the helm chart of our app. Whenever a new release is tagged on the master branch for this helm chart git repo we'll upgrade the helm chart release in our Kubernetes Cluster, which in turn will upgrade our http-server app in our Kubernetes cluster.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--OCjf3lsV--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://www.socketxp.com/wp-content/uploads/2020/07/Kubernetes-autoupdate-github-webhook-helm-chart.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--OCjf3lsV--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://www.socketxp.com/wp-content/uploads/2020/07/Kubernetes-autoupdate-github-webhook-helm-chart.png" alt="Kubernetes-autoupdate-github-webhook-helm-chart" width="800" height="600"&gt;&lt;/a&gt;&lt;/p&gt;

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

&lt;p&gt;We'll use the same demo app we used in our last week's demo. I'm displaying it again over here for convenience.&lt;/p&gt;

&lt;pre&gt;$cat http-server.js 
var http = require('http');
var port = 8080
var handleRequest = function(request, response) {
  console.log('Received HTTP request for URL: ' + request.url);
  response.writeHead(200);
  response.end('Hello World!, v1.0');
};
var server = http.createServer(handleRequest);
server.listen(port); 
&lt;/pre&gt;

&lt;p&gt;Also the Dockerfile used to build our http-server app from our last week's demo.&lt;/p&gt;

&lt;pre&gt;FROM alpine:latest
RUN apk update &amp;amp;&amp;amp; apk add nodejs
RUN mkdir -p /usr/src/app
COPY ./http-server.js /usr/src/app
WORKDIR /usr/src/app
EXPOSE 8080 
CMD ["node","http-server.js"]
&lt;/pre&gt;

&lt;p&gt;Refer to our &lt;a href="https://www.socketxp.com/webhookrelay/docker-compose-auto-update-github-webhook/"&gt;&lt;b&gt;last week's demo article&lt;/b&gt;&lt;/a&gt; on how to build a version 1.0 of the docker image and publish it to a DockerHub registry.&lt;/p&gt;

&lt;h2&gt;Kubernetes Cluster&lt;/h2&gt;

&lt;p&gt;Install Kubernetes Cluster or a Minikube Cluster following the instructions here:&lt;/p&gt;

&lt;ul&gt;
    &lt;li&gt;&lt;a href="http://www.ethernetresearch.com/geekzone/kubernetes-tutorial-how-to-install-kubernetes-on-ubuntu/"&gt;How to install Kubernetes on Ubuntu&lt;/a&gt;&lt;/li&gt;
    &lt;li&gt;&lt;a href="http://www.ethernetresearch.com/kubernetes/kubernetes-how-to-install-minikube-in-a-vm/"&gt;How to install minikube in a VM&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Check the nodes and the pods available.&lt;/p&gt;

&lt;pre&gt;$kubectl get nodes
NAME       STATUS   ROLES    AGE     VERSION
minikube   Ready    master   3h45m   v1.18.3
&lt;/pre&gt;

&lt;pre&gt;$kubectl get pods
No resources found in default namespace.
$
&lt;/pre&gt;

&lt;h2&gt;Helm&lt;/h2&gt;

&lt;p&gt;I have already created an helm chart for this demo and is available at: &lt;b&gt;&lt;a href="https://github.com/socketxp-com/kubernetes-webhook-autoupdate-helm-chart"&gt;&lt;/a&gt;&lt;a href="https://github.com/socketxp-com/kubernetes-webhook-autoupdate-helm-chart"&gt;https://github.com/socketxp-com/kubernetes-webhook-autoupdate-helm-chart&lt;/a&gt;&lt;/b&gt;&lt;/p&gt;

&lt;p&gt;But if you want to create your own helm chart follow the instructions below to install helm and create a helm chart.&lt;/p&gt;

&lt;pre&gt;$ brew install helm
&lt;/pre&gt;

&lt;pre&gt;$ helm create http-server-chart
$ ls
http-server-chart
$ cd http-server-chart
$ ls
Chart.yaml  charts      templates   values.yaml
$
&lt;/pre&gt;

&lt;p&gt;Now edit the values.yaml file and update the repository and tag fields to your app's docker image name and tag. Also update templates such as deployment.yaml or service.yaml under the templates folder, if required.&lt;/p&gt;

&lt;p&gt;Commit the changes to your chart into a git repository, so that the changes/versions can be tracked. Also this will help in upgrading the corresponding workloads in a Kubernetes cluster, in a GitOps fashion.&lt;/p&gt;

&lt;h2&gt;Run SocketXP on the master node&lt;/h2&gt;

&lt;p&gt;Download and install SocketXP agent on the master node of your Kubernetes cluster's master node. You can follow the &lt;a href="https://www.socketxp.com/download/"&gt;&lt;b&gt;SocketXP download instructions here&lt;/b&gt;&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Next jump into the root directory of the git cloned chart repo and execute the below command. The repo already has the files "update-kube.sh" and "filter-rules.sh" from the last week's demo. The only change is in the update-kube.sh file to execute a "helm upgrade" command instead of "docker-compose up -d" command.&lt;/p&gt;

&lt;pre&gt;$ cat update-kube.sh
#!/bin/bash

git pull
helm upgrade http-server http-server-chart
&lt;/pre&gt;

&lt;p&gt;Execute the SocketXP relay command.&lt;/p&gt;

&lt;pre&gt;$ socketxp relay http://localhost:8443 --exec ./update-kube.sh --filter filter-rules.json

connected.
Public URL -&amp;gt; https://webhook.socketxp.com/ganeshvelrajan-rmzlayq9
&lt;/pre&gt;

&lt;p&gt;Now pick up this SocketXP Public Webhook URL and go to your GitHub Webhook Settings page and paste this URL in the Public Webhook URL text box. Make sure you set the content type of GitHub webhook to "application/json". Also set the secret with your own secret. This secret will be used to validate the sender when a GitHub webhook is received at your Kubernetes Cluster master node.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--wNHYuWpX--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://www.socketxp.com/wp-content/uploads/2020/07/Kubernetes-Github-Webhook-.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--wNHYuWpX--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://www.socketxp.com/wp-content/uploads/2020/07/Kubernetes-Github-Webhook-.png" alt="Kubernetes Github Webhook-socketxp" width="800" height="580"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;Install Helm Chart&lt;/h2&gt;

&lt;p&gt;Install the helm chart manually using the following command and bring up the http-server app in the kubernetes cluster. We need to do this only once when we bring up the app for the very first time. Thereafter, we'll automate the upgrade process using SocketXP.&lt;/p&gt;

&lt;pre&gt;$ls
LICENSE         filter-rules.json   update-kube.sh
README.md       http-server-chart
$helm install http-server http-server-chart/
NAME: http-server
LAST DEPLOYED: Fri Jul 10 11:59:39 2020
NAMESPACE: default
STATUS: deployed
REVISION: 1
NOTES:
1. Get the application URL by running these commands:
  export NODE_PORT=$(kubectl get --namespace default -o jsonpath="{.spec.ports[0].nodePort}" services http-server-http-server-chart)
  export NODE_IP=$(kubectl get nodes --namespace default -o jsonpath="{.items[0].status.addresses[0].address}")
  echo http://$NODE_IP:$NODE_PORT
&lt;/pre&gt;

&lt;p&gt;Let's follow the instructions in the above output and copy paste the above commands.&lt;/p&gt;

&lt;pre&gt;$export NODE_PORT=$(kubectl get --namespace default -o jsonpath="{.spec.ports[0].nodePort}" services http-server-http-server-chart)
  export NODE_IP=$(kubectl get nodes --namespace default -o jsonpath="{.items[0].status.addresses[0].address}")
$  export NODE_IP=$(kubectl get nodes --namespace default -o jsonpath="{.items[0].status.addresses[0].address}")
$echo http://$NODE_IP:$NODE_PORT
http://192.168.99.100:32194
$
&lt;/pre&gt;

&lt;p&gt;Let's try to access our http-server application at the above mentioned URL.&lt;/p&gt;

&lt;pre&gt;$curl http://192.168.99.100:32194
Hello World!, v1.0
&lt;/pre&gt;

&lt;p&gt;Great. Our app is running version 1.0 as expected.&lt;br&gt;
Next verify the helm release version currently deployed.&lt;/p&gt;

&lt;pre&gt;$helm ls
NAME        NAMESPACE   REVISION    UPDATED                                 STATUS      CHART                   APP VERSION
http-server default     1           2020-07-10 11:59:39.651311 +0530 IST    deployed    http-server-chart-0.1.0 1.16.0  
&lt;/pre&gt;

&lt;h2&gt;Begin Demo - Upgrade the app and the chart&lt;/h2&gt;

&lt;p&gt;Now let's edit our http-server app like we did in the last week's demo and push a docker container image version 2.0 to DockerHub. Please refer to our last week's demo article if you forgot the instruction for doing so.&lt;/p&gt;

&lt;p&gt;Next let's edit the helm-chart and upgrade the image version and the chart version to 2.0 and 0.2.0 respectively.&lt;/p&gt;

&lt;pre&gt;
$vim http-server-chart/values.yaml
# Default values for http-server-chart.
# This is a YAML-formatted file.
# Declare variables to be passed into your templates.

replicaCount: 1

image:
  repository: gvelrajan/http-server
  pullPolicy: IfNotPresent
  # Overrides the image tag whose default is the chart appVersion.
  &lt;b&gt;tag: "v2.0"&lt;/b&gt;
...
...
&lt;/pre&gt;

&lt;pre&gt;
...
# This is the chart version. This version number should be incremented each time you make changes
# to the chart and its templates, including the app version.
# Versions are expected to follow Semantic Versioning (https://semver.org/)
&lt;b&gt;version: 0.2.0&lt;/b&gt;
...
...
&lt;/pre&gt;

&lt;p&gt;Commit the changes and push to GitHub.&lt;/p&gt;

&lt;pre&gt; 
$git add .
$git commit -m "image version and chart version updated"
[master 1765b2e] image version and chart version updated
 4 files changed, 35 insertions(+), 2 deletions(-)
 create mode 100644 filter-rules.json
 create mode 100755 update-kube.sh
$git push
Counting objects: 7, done.
Delta compression using up to 8 threads.
Compressing objects: 100% (7/7), done.
Writing objects: 100% (7/7), 839 bytes | 839.00 KiB/s, done.
Total 7 (delta 3), reused 0 (delta 0)
remote: Resolving deltas: 100% (3/3), completed with 3 local objects.
To https://github.com/socketxp-com/kubernetes-webhook-autoupdate-helm-chart.git
   2f12153..1765b2e  master -&amp;gt; master
&lt;/pre&gt;

&lt;p&gt;As soon as we do git push for the chart into its online repo, GitHub will trigger a webhook notification for the git push event. SocketXP will receive the webhook, validate the signature and try to match it with the fiter rules. Since this is not a release webhook, SocketXP will throw a mismatch error and not further process this webhook.&lt;/p&gt;

&lt;pre&gt;Connected.
Public URL -&amp;gt; https://webhook.socketxp.com/ganeshvelrajan-rmzlayq9

Webhook received:
POST / HTTP/1.1
Host: webhook.socketxp.com
Accept: */*
Accept-Encoding: gzip
Content-Length: 9397
Content-Type: application/json
User-Agent: GitHub-Hookshot/f2f2346
X-Github-Delivery: 4aba8354-c279-11ea-980e-6cd6cfda12a3
X-Github-Event: push
X-Hub-Signature: sha1=14e1f0a3d368d9b5dadd7d41cd575af2f45065ce

{"ref":"refs/heads/master","before":"2f12153ef944b939bc81712e1d047d281d2deabe","after":"1765b2ecd58ad3c6d3fec15c7b3198063b543405","repository":{"id":278398971,"node_id":"MDEwOlJlcG9zaXRvcnkyNzgzOTg5NzE=","name":"kubernetes-webhook-autoupdate-helm-chart",
...
]}}

&lt;b&gt;#Rule: Webhook signature matched.
#Rule: ref in payload didn't match
Webhook received didn't match with the filter rules.
Command not executed.&lt;/b&gt;
&lt;/pre&gt;

&lt;h2&gt;Release version 0.2.0 of the chart&lt;/h2&gt;

&lt;p&gt;So this proves that our http-server app will not be upgraded on receiving just any ad-hoc wehbook notifications from GitHub. It gets upgraded only on receiving an official release webhook for the app's helm chart.&lt;/p&gt;

&lt;p&gt;Now, let's go ahead and create an official release version 0.2.0 of the helm chart for our app. We do this in the GitHub release page for our app's helm-chart repo.&lt;/p&gt;

&lt;p&gt;[ Note: But before doing this make sure you update the print string in our http-server app to print "v2.0".  Also build a new Docker container image for the upgraded app and tag it as v2.0.   Refer to our last week'd demo if you need to know how to perform these actions]&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--qOIAagQ_--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://www.socketxp.com/wp-content/uploads/2020/07/Helm-Chart-Release-Version-0.2.0.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--qOIAagQ_--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://www.socketxp.com/wp-content/uploads/2020/07/Helm-Chart-Release-Version-0.2.0.png" alt="Kubernetes Continuous Deployment Helm Chart GitHub Webhook" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;SocketXP will receive the release webhook from GitHub. It will process the webhook, validate the signature and match the ref field in the webhook payload with the filter rules.&lt;/p&gt;

&lt;pre&gt;Webhook received:
POST / HTTP/1.1
Host: webhook.socketxp.com
Accept: */*
Accept-Encoding: gzip
Content-Length: 8725
Content-Type: application/json
User-Agent: GitHub-Hookshot/f2f2346
X-Github-Delivery: b08b5ec8-c27a-11ea-8774-72206af92c06
X-Github-Event: push
X-Hub-Signature: sha1=d6fefb9919e8b322226f6dcd485bd2f2591e80c8

{"ref":"refs/tags/v0.2.0","before":"0000000000000000000000000000000000000000","after":"1765b2ecd58ad3c6d3fec15c7b3198063b543405","repository":{"id":278398971,"node_id":"MDEwOlJlcG9zaXRvcnkyNzgzOTg5NzE=","name":"kubernetes-webhook-autoupdate-helm-chart","full_name":"socketxp-com/kubernetes-webhook-autoupdate-helm-chart",
...
...

]}}

&lt;b&gt;#Rule: Webhook signature matched.
#Rule: ref in payload matched.
All rules matched.&lt;/b&gt;

Executing command:  [./update-kube.sh]
From https://github.com/socketxp-com/kubernetes-webhook-autoupdate-helm-chart
 * [new tag]         v0.2.0     -&amp;gt; v0.2.0
Already up to date.
Current branch master is up to date.
Release "http-server" has been upgraded. Happy Helming!
NAME: http-server
LAST DEPLOYED: Fri Jul 10 12:42:09 2020
NAMESPACE: default
STATUS: deployed
REVISION: 2
NOTES:
1. Get the application URL by running these commands:
  export NODE_PORT=$(kubectl get --namespace default -o jsonpath="{.spec.ports[0].nodePort}" services http-server-http-server-chart)
  export NODE_IP=$(kubectl get nodes --namespace default -o jsonpath="{.items[0].status.addresses[0].address}")
  echo http://$NODE_IP:$NODE_PORT
&lt;/pre&gt;

&lt;p&gt;Let's follow the instructions above output and copy paste the above commands in a separate terminal.&lt;/p&gt;

&lt;pre&gt;$  export NODE_PORT=$(kubectl get --namespace default -o jsonpath="{.spec.ports[0].nodePort}" services http-server-http-server-chart)
$  export NODE_IP=$(kubectl get nodes --namespace default -o jsonpath="{.items[0].status.addresses[0].address}")
$  echo http://$NODE_IP:$NODE_PORT
http://192.168.99.100:32194
&lt;/pre&gt;

&lt;p&gt;Now, let's access the URL using curl.&lt;/p&gt;

&lt;pre&gt;$curl http://192.168.99.100:32194
Hello World!, v2.0
&lt;/pre&gt;

&lt;p&gt;Also confirm the kubernetes workload(pod) has the correct versions.&lt;/p&gt;

&lt;pre&gt;$kubectl describe  pods
Name:         http-server-http-server-chart-5947946f5f-vb5cn
Namespace:    default
Priority:     0
Node:         minikube/192.168.99.100
Start Time:   Fri, 10 Jul 2020 02:30:00 +0530
Labels:       app.kubernetes.io/instance=http-server
              app.kubernetes.io/name=http-server-chart
              pod-template-hash=5947946f5f
Annotations:  
Status:       Running
IP:           172.17.0.5
IPs:
  IP:           172.17.0.5
Controlled By:  ReplicaSet/http-server-http-server-chart-5947946f5f
Containers:
  http-server-chart:
    Container ID:   docker://7deb29b8786bc474374be82b27c33858cad8ec4b86754c29ad6467bf41f4ecc9
    &lt;b&gt;Image:          gvelrajan/http-server:v2.0&lt;/b&gt;
    Image ID:       docker-pullable://gvelrajan/http-server@sha256:2a9ee82f76758758c77659260091380b20e3b3d095efdc6480d66e47c5842476
    Port:           8080/TCP
    Host Port:      0/TCP
    State:          Running
      Started:      Fri, 10 Jul 2020 02:30:03 +0530
    Ready:          True
    Restart Count:  0
    Liveness:       http-get http://:http/ delay=0s timeout=1s period=10s #success=1 #failure=3
    Readiness:      http-get http://:http/ delay=0s timeout=1s period=10s #success=1 #failure=3
    Environment:    
    Mounts:
      /var/run/secrets/kubernetes.io/serviceaccount from http-server-http-server-chart-token-rmppc (ro)
Conditions:
  Type              Status
  Initialized       True 
  Ready             True 
  ContainersReady   True 
  PodScheduled      True 
Volumes:
  http-server-http-server-chart-token-rmppc:
    Type:        Secret (a volume populated by a Secret)
    SecretName:  http-server-http-server-chart-token-rmppc
    Optional:    false
QoS Class:       BestEffort
Node-Selectors:  
Tolerations:     node.kubernetes.io/not-ready:NoExecute for 300s
                 node.kubernetes.io/unreachable:NoExecute for 300s
Events:
  Type    Reason     Age   From               Message
  ----    ------     ----  ----               -------
  Normal  Scheduled  10h   default-scheduler  Successfully assigned default/http-server-http-server-chart-5947946f5f-vb5cn to minikube
  Normal  Pulled     10h   kubelet, minikube  Container image "gvelrajan/http-server:v2.0" already present on machine
  Normal  Created    10h   kubelet, minikube  Created container http-server-chart
  Normal  Started    10h   kubelet, minikube  Started container http-server-chart
$

&lt;/pre&gt;

&lt;p&gt;Also let's check the helm release version currently deployed.&lt;/p&gt;

&lt;pre&gt;$helm ls
NAME        NAMESPACE   REVISION    UPDATED                                 STATUS      CHART                   APP VERSION
http-server default     2           2020-07-10 12:42:09.288038 +0530 IST    deployed    http-server-chart-0.2.0 1.16.0     
$
&lt;/pre&gt;

&lt;p&gt;Everything confirms that we are have successfully upgraded our app to version 2.0 by upgrading the helm chart release version to 0.2.0&lt;/p&gt;

&lt;h2&gt;Rolling back to the previous working version&lt;/h2&gt;

&lt;p&gt;Suppose, the upgrade to version 2.0 of the app introduced some severe bugs or problems that is unacceptable by any user, we would want to quickly go back to the previous working version, so that customers are not affected by our upgrade.&lt;/p&gt;

&lt;p&gt;Helm makes the process of rollback very simple. Let's do it. We'll rollback to revision #1 of the helm chart from revision #2.&lt;/p&gt;

&lt;pre&gt;$helm rollback http-server 1
Rollback was a success! Happy Helming!
$helm ls
NAME        NAMESPACE   REVISION    UPDATED                                 STATUS      CHART                   APP VERSION
http-server default     3           2020-07-10 12:53:04.755063 +0530 IST    deployed    http-server-chart-0.1.0 1.16.0     
&lt;/pre&gt;

&lt;p&gt;Curl the app's web URL and verify if the rollback is successful.&lt;/p&gt;

&lt;pre&gt;$curl http://192.168.99.100:32194
Hello World!, v1.0
&lt;/pre&gt;

&lt;p&gt;Verify the pods running in the Kubernetes cluster have the right version. Notice that the pod running the old version of our http-server app is terminating and the pod running the new version is up and running.&lt;/p&gt;

&lt;pre&gt;$kubectl describe  pods
Name:                      http-server-http-server-chart-5947946f5f-vb5cn
Namespace:                 default
Priority:                  0
Node:                      minikube/192.168.99.100
Start Time:                Fri, 10 Jul 2020 02:30:00 +0530
Labels:                    app.kubernetes.io/instance=http-server
                           app.kubernetes.io/name=http-server-chart
                           pod-template-hash=5947946f5f
Annotations:               
&lt;b&gt;Status:                    Terminating (lasts 10h)&lt;/b&gt;
Termination Grace Period:  30s
IP:                        172.17.0.5
IPs:
  IP:           172.17.0.5
Controlled By:  ReplicaSet/http-server-http-server-chart-5947946f5f
Containers:
  http-server-chart:
    Container ID:   docker://7deb29b8786bc474374be82b27c33858cad8ec4b86754c29ad6467bf41f4ecc9
    Image:          gvelrajan/http-server:v2.0
    Image ID:       docker-pullable://gvelrajan/http-server@sha256:2a9ee82f76758758c77659260091380b20e3b3d095efdc6480d66e47c5842476
    Port:           8080/TCP
    Host Port:      0/TCP
    State:          Running
      Started:      Fri, 10 Jul 2020 02:30:03 +0530
    Ready:          True
    Restart Count:  0
    Liveness:       http-get http://:http/ delay=0s timeout=1s period=10s #success=1 #failure=3
    Readiness:      http-get http://:http/ delay=0s timeout=1s period=10s #success=1 #failure=3
    Environment:    
    Mounts:
      /var/run/secrets/kubernetes.io/serviceaccount from http-server-http-server-chart-token-rmppc (ro)
Conditions:
  Type              Status
  Initialized       True 
  Ready             True 
  ContainersReady   True 
  PodScheduled      True 
Volumes:
  http-server-http-server-chart-token-rmppc:
    Type:        Secret (a volume populated by a Secret)
    SecretName:  http-server-http-server-chart-token-rmppc
    Optional:    false
QoS Class:       BestEffort
Node-Selectors:  
Tolerations:     node.kubernetes.io/not-ready:NoExecute for 300s
                 node.kubernetes.io/unreachable:NoExecute for 300s
Events:
  Type    Reason     Age   From               Message
  ----    ------     ----  ----               -------
  Normal  Scheduled  10h   default-scheduler  Successfully assigned default/http-server-http-server-chart-5947946f5f-vb5cn to minikube
  Normal  Pulled     10h   kubelet, minikube  Container image "gvelrajan/http-server:v2.0" already present on machine
  Normal  Created    10h   kubelet, minikube  Created container http-server-chart
  Normal  Started    10h   kubelet, minikube  Started container http-server-chart
  Normal  Killing    10h   kubelet, minikube  Stopping container http-server-chart


Name:         http-server-http-server-chart-bdd75ff4-7jmbx
Namespace:    default
Priority:     0
Node:         minikube/192.168.99.100
Start Time:   Fri, 10 Jul 2020 02:40:56 +0530
Labels:       app.kubernetes.io/instance=http-server
              app.kubernetes.io/name=http-server-chart
              pod-template-hash=bdd75ff4
Annotations:  
&lt;b&gt;Status:       Running&lt;/b&gt;
IP:           172.17.0.4
IPs:
  IP:           172.17.0.4
Controlled By:  ReplicaSet/http-server-http-server-chart-bdd75ff4
Containers:
  http-server-chart:
    Container ID:   docker://239aadd09eb54185b3aa559d5ba3a89f2cb99a30c5b340270b834f9e25de24cb
    Image:          gvelrajan/http-server:v1.0
    Image ID:       docker-pullable://gvelrajan/http-server@sha256:07e70e778e1002519064503ece0d334291f4fbb7a7196b894f605ff5e3076e18
    Port:           8080/TCP
    Host Port:      0/TCP
    State:          Running
      Started:      Fri, 10 Jul 2020 02:40:57 +0530
    Ready:          True
    Restart Count:  0
    Liveness:       http-get http://:http/ delay=0s timeout=1s period=10s #success=1 #failure=3
    Readiness:      http-get http://:http/ delay=0s timeout=1s period=10s #success=1 #failure=3
    Environment:    
    Mounts:
      /var/run/secrets/kubernetes.io/serviceaccount from http-server-http-server-chart-token-rmppc (ro)
Conditions:
  Type              Status
  Initialized       True 
  Ready             True 
  ContainersReady   True 
  PodScheduled      True 
Volumes:
  http-server-http-server-chart-token-rmppc:
    Type:        Secret (a volume populated by a Secret)
    SecretName:  http-server-http-server-chart-token-rmppc
    Optional:    false
QoS Class:       BestEffort
Node-Selectors:  
Tolerations:     node.kubernetes.io/not-ready:NoExecute for 300s
                 node.kubernetes.io/unreachable:NoExecute for 300s
Events:
  Type    Reason     Age   From               Message
  ----    ------     ----  ----               -------
  Normal  Scheduled  10h   default-scheduler  Successfully assigned default/http-server-http-server-chart-bdd75ff4-7jmbx to minikube
  Normal  Pulled     10h   kubelet, minikube  Container image "gvelrajan/http-server:v1.0" already present on machine
  Normal  Created    10h   kubelet, minikube  Created container http-server-chart
  Normal  Started    10h   kubelet, minikube  Started container http-server-chart
$
&lt;/pre&gt;

&lt;p&gt;That's all folks!! I hope you were able to follow the instructions and auto deploy your app in Kubernetes using SocketXP and Helm chart in a GitOps fashion.&lt;/p&gt;

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

&lt;p&gt;SocketXP and Helm are two great tools to setup a full-automated Continuous Deployment(CD) pipeline for your app running in your Kubernetes Cluster. Though you might want to expose your app ( a front-end microservice) running in your Kubernetes Cluster to the internet, you wouldn't want to and shouldn't expose your Kubernetes Cluster itself to the internet.&lt;/p&gt;

&lt;p&gt;When you are not exposing the Kubernetes Cluster to the internet, it may be challenging to receive webhook notifications from GitHub, Gitlab, DockerHub, GCR and other online version control and artifact repositories. SocketXP solves this problem by quickly creating a secure webhook relay tunnel between the online registry and your Kubernetes Cluster, so that webhooks could reach your private Kubernetes Cluster.&lt;/p&gt;

&lt;p&gt;SocketXP is a freemium online webhook relay service, which has free and paid plans for developers, businesses and enterprise customers. &lt;a href="https://portal.socketxp.com"&gt;&lt;b&gt;Sign up for your free SocketXP account here&lt;/b&gt;&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;b&gt;This article was originally published at:&lt;/b&gt;&lt;br&gt;
&lt;a href="https://www.socketxp.com/webhookrelay/autoupdate-kubernetes-deployment-on-github-webhook/"&gt;&lt;/a&gt;&lt;a href="https://www.socketxp.com/webhookrelay/autoupdate-kubernetes-deployment-on-github-webhook/"&gt;https://www.socketxp.com/webhookrelay/autoupdate-kubernetes-deployment-on-github-webhook/&lt;/a&gt;&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Docker Compose Auto Update on GitHub Webhook</title>
      <dc:creator>gvelrajan</dc:creator>
      <pubDate>Sat, 04 Jul 2020 07:28:48 +0000</pubDate>
      <link>https://dev.to/gvelrajan/docker-compose-auto-update-on-github-webhook-2hn8</link>
      <guid>https://dev.to/gvelrajan/docker-compose-auto-update-on-github-webhook-2hn8</guid>
      <description>&lt;p&gt;In the last week's demo, I showed how to setup a &lt;a href="https://www.socketxp.com/webhookrelay/automatically-deploy-github-local-server-git-push/"&gt;&lt;b&gt;Continuous Deployment(CD) pipeline for a native NodeJS application&lt;/b&gt;&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;In this article, I'll show you how to build a GitOps style CD pipeline that keeps a Docker Compose deployment in sync with a docker-compose YAML file hosted on a git repository.&lt;/p&gt;

&lt;h2&gt;What's new in this demo?&lt;/h2&gt;

&lt;p&gt;We have added some cool new features to SocketXP agent, such as:&lt;/p&gt;

&lt;ul&gt;
    &lt;li&gt;ability to filter incoming webhooks on user specified filter rules&lt;/li&gt;
    &lt;li&gt;ability to execute a command or a script file when an incoming webhook matches with the user specified rules&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Secondly, and more importantly, we'll be running our NodeJS web app inside a Docker container and bring it up using a Docker Compose YAML file.&lt;/p&gt;

&lt;h2&gt;Prerequisites&lt;/h2&gt;

&lt;p&gt;Here are the prerequisites for this demo.&lt;/p&gt;

&lt;ul&gt;
    &lt;li&gt;GitHub&lt;/li&gt;
    &lt;li&gt;SocketXP Account&lt;/li&gt;
    &lt;li&gt;SocketXP Agent Installation&lt;/li&gt;
    &lt;li&gt;Docker Engine, Docker Compose and DockerHub Account&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--2vHWE2kx--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://www.socketxp.com/wp-content/uploads/2020/07/Docker-compose-auto-update-github-webhook.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--2vHWE2kx--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://www.socketxp.com/wp-content/uploads/2020/07/Docker-compose-auto-update-github-webhook.png" alt="Docker-compose-auto-update-github-webhook" width="800" height="600"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Repository with scripts that I used for this article can be found here: &lt;a href="https://github.com/socketxp-com/docker-compose-autoupdate-on-github-webhook"&gt;&lt;/a&gt;&lt;a href="https://github.com/socketxp-com/docker-compose-autoupdate-on-github-webhook"&gt;https://github.com/socketxp-com/docker-compose-autoupdate-on-github-webhook&lt;/a&gt;.&lt;/p&gt;

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

&lt;p&gt;We'll use the same nodejs http server that we used in the last week's demo.&lt;/p&gt;

&lt;pre&gt;$cat http-server.js 
var http = require('http');
var port = 8080
var handleRequest = function(request, response) {
  console.log('Received HTTP request for URL: ' + request.url);
  response.writeHead(200);
  response.end('Hello World!, v1.0');
};
var server = http.createServer(handleRequest);
server.listen(port); 
&lt;/pre&gt;

&lt;h2&gt;Dockerfile&lt;/h2&gt;

&lt;p&gt;Here is the Dockerfile we'll use to package the above nodejs app into a Docker container.&lt;/p&gt;

&lt;pre&gt;FROM alpine:latest
RUN apk update &amp;amp;&amp;amp; apk add nodejs
RUN mkdir -p /usr/src/app
COPY ./http-server.js /usr/src/app
WORKDIR /usr/src/app
EXPOSE 8080 
CMD ["node","http-server.js"]
&lt;/pre&gt;

&lt;p&gt;Let's build the Docker image using the following Docker command.&lt;/p&gt;

&lt;pre&gt;$docker build -t gvelrajan/http-server:v1.0 .
Sending build context to Docker daemon  56.83kB
Step 1/7 : FROM alpine:latest
 ---&amp;gt; f70734b6a266
Step 2/7 : RUN apk update &amp;amp;&amp;amp; apk add nodejs
 ---&amp;gt; Using cache
...
Successfully built b6b06a819b63
Successfully tagged gvelrajan/http-server:v1.0
$
&lt;/pre&gt;

&lt;p&gt;Next, let's push this Docker image to DockerHub image registry, so that it can be downloaded by the production team to deploy it.&lt;/p&gt;

&lt;pre&gt;$docker push gvelrajan/http-server:v1.0
The push refers to repository [docker.io/gvelrajan/http-server]
3b8d0f6b058e: Layer already exists 
947da554eff8: Layer already exists 
cc403a71dcfb: Pushed 
3e207b409db3: Layer already exists 
v1.0: digest: sha256:07e70e778e1002519064503ece0d334291f4fbb7a7196b894f605ff5e3076e18 size: 1154
&lt;/pre&gt;

&lt;h2&gt;Docker Compose&lt;/h2&gt;

&lt;p&gt;Docker Compose is a very helpful tool to bring up various services of an application as Docker containers using a simple single command. In our demo example we have just a single service - the http web service, packaged as a Docker container.&lt;/p&gt;

&lt;p&gt;Here is the docker-compose yaml file we'll use to bring up our http-server docker container in production.&lt;/p&gt;

&lt;pre&gt;$cat docker-compose.yml 
version: '3'
services:
  web:
    image: "gvelrajan/http-server:v1.0"
    ports:
      - "8080:8080"
$
&lt;/pre&gt;

&lt;p&gt;Now, bring up the app container by executing the following command.&lt;/p&gt;

&lt;pre&gt;$docker-compose up -d
Creating network "docker-compose-autoupdate-on-github-webhook_default" with the default driver
Creating docker-compose-autoupdate-on-github-webhook_web_1_fd2bb2cedec9 ... done
&lt;/pre&gt;

&lt;p&gt;Check if the docker container is up and running, and listening on the correct port(8080).&lt;/p&gt;

&lt;pre&gt;$docker ps
CONTAINER ID        IMAGE                        COMMAND                 CREATED             STATUS              PORTS                    NAMES
899ab99abedf        gvelrajan/http-server:v1.0   "node http-server.js"   2 seconds ago       Up 1 second         0.0.0.0:8080-&amp;gt;8080/tcp   docker-compose-autoupdate-on-github-webhook_web_1_64dc034e55ac
$
&lt;/pre&gt;

&lt;h2&gt;Curl the web server&lt;/h2&gt;

&lt;p&gt;Verify that our web app is running and serving content on port 8080.&lt;/p&gt;

&lt;pre&gt;$curl http://localhost:8080
Hello World!, v1.0
&lt;/pre&gt;

&lt;p&gt;Our initial deployment is very successful. But this was a manual deployment. Every time a newer version of the app is released we have to manually download and deploy the application. This is not what we wanted. Our goal for this demo is to build a Continuous Deployment(CD) pipeline for our nodejs based web service running as a docker container.&lt;/p&gt;

&lt;p&gt;Let's begin by setting up various stages in the CD pipeline, like we did in the last week's demo.&lt;/p&gt;

&lt;h2&gt;Auto deployment strategy&lt;/h2&gt;

&lt;p&gt;Our auto deployment strategy has changed and is slightly different from the one used in the last week's native app demo. Here is the auto deployment strategy for this demo:&lt;/p&gt;

&lt;p&gt;When a new version of our app is available, we'll update the docker-compose.yml file in the GitHub and release a new version of our app in the GitHub. GitHub will trigger a webhook for this release event. We'll listen for this webhook event and automatically do a git pull on the docker-compose.yml file. We'll use the new docker-compose.yml to re-spin our nodejs web service docker container in production.&lt;/p&gt;

&lt;p&gt;&lt;b&gt;Note:&lt;/b&gt; GitHub will trigger webhooks for all sorts of push events. We don't want to react to all those webhooks and auto deploy our containers on every GitHub push. We want to auto deploy only when a new release is made.&lt;/p&gt;

&lt;h2&gt;SocketXP Webhook Relay Service&lt;/h2&gt;

&lt;p&gt;We'll use &lt;b&gt;&lt;a href="https://www.socketxp.com"&gt;SocketXP Webhook Relay Service&lt;/a&gt;&lt;/b&gt; to relay webhooks from GitHub to our local production server (where the nodejs app is running as a docker container). SocketXP can also filter GitHub webhooks based on user specified rules in JSON format. We'll discuss more about it in the next section. Additionally, SocketXP can execute a script or a command, if an incoming webhook matches with the user specified rules.&lt;/p&gt;

&lt;p&gt;Before creating webhook rules, it is better to study the webhook in detail and pick up a few fields in the webhook payload to match on. For this we need to make GitHub trigger a release webhook and capture the webhook and study it.&lt;/p&gt;

&lt;h2&gt;Webhook Capture and Study&lt;/h2&gt;

&lt;p&gt;First, let's setup the SocketXP agent to relay any webhooks from the internet to our local web service.&lt;/p&gt;

&lt;pre&gt;$ socketxp relay http://localhost:8080

Connected.
Public URL -&amp;gt; https://webhook.socketxp.com/ganeshvelrajan-1awy5t0h
&lt;/pre&gt;

&lt;p&gt;Pick up the above SocketXP Public URL and head to your GitHub repository. Setup the webhook settings for your GitHub project as shown below. Setup your secret and copy paste the SocketXP Public URL in the webhook URL text box. Also set the content-type to "application/json" in the drop-down box. Save the changes.&lt;br&gt;
&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--Vu6TAKuZ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/i/akqgsppi4hi0c6frj6c9.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--Vu6TAKuZ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/i/akqgsppi4hi0c6frj6c9.png" alt="Alt Text" width="800" height="554"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;Triggering GitHub Release Webhook&lt;/h2&gt;

&lt;p&gt;Next, create a new release for your GitHub project in the release settings page and create a new tag for your release, as shown below.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--AJEBQoDb--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/i/3iqxll4jbg2tk66m6nex.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--AJEBQoDb--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/i/3iqxll4jbg2tk66m6nex.png" alt="Alt Text" width="800" height="396"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;GitHub will trigger a webhook for this release event in your project. We can view details of the triggered webhook either in the GitHub Webhook Settings page or in the SocketXP Portal Webhook Logs page.&lt;/p&gt;

&lt;pre&gt;Request URL: https://webhook.socketxp.com/ganeshvelrajan-1awy5t0h
Request method: POST
Accept: */*
content-type: application/json
User-Agent: GitHub-Hookshot/e509757
X-GitHub-Delivery: ca631384-bd0e-11ea-8ba6-ea05e17356b6
X-GitHub-Event: push
&lt;b&gt;X-Hub-Signature: sha1=c902f69547901dc0658ba54eaee5cde6c0a5ef00&lt;/b&gt;

{
  &lt;b&gt;"ref": "refs/tags/v1.0",&lt;/b&gt;
  "before": "0000000000000000000000000000000000000000",
  "after": "b5595d43b2c681257e0bae638f9de814df968901",
  "repository": {
    "id": 276817731,
    "node_id": "MDEwOlJlcG9zaXRvcnkyNzY4MTc3MzE=",
    "name": "docker-compose-autoupdate-on-github-webhook",
    "full_name": "socketxp-com/docker-compose-autoupdate-on-github-webhook",
    "private": false,
    ...
    ...
}
&lt;/pre&gt;

&lt;p&gt;In the above webhook capture, we see the signature field in the header that encodes the secret we set in the GitHub webhook settings page. Verifying this signature using the secrete we provided, authenticates the validity of the sender.&lt;/p&gt;

&lt;p&gt;Secondly, in the above webhook capture, the payload contains the release tags ("refs/tags/v1.0") in the "ref" field.&lt;/p&gt;

&lt;p&gt;Let's try to filter our incoming webhook based on these two fields in the webhook.&lt;/p&gt;

&lt;h2&gt;SocketXP Webhook Filter-Rules JSON File&lt;/h2&gt;

&lt;p&gt;Here is how the SocketXP filter-rules JSON file should look like to match the two fields we picked up in the webhook above.&lt;/p&gt;

&lt;pre&gt;$cat filter-rules.json 
{
  "and":
  [
    {
      "match":
      {
        "type": "payload-hash-sha1",
        "secret": "asdfasdf23421dsaf",    
        "parameter":
        {
          "source": "header",
          "name": "X-Hub-Signature"
        }
      }
    },
    {
      "match":
      {
        "type": "value",
        "value": "refs/tags",
        "parameter":
        {
          "source": "payload",
          "name": "ref"
        }
      }
    }
  ]
}&lt;/pre&gt;
Make sure you update the "secret" field in the filter-rules file above with your GitHub webhook secret.
&lt;h2&gt;SocketXP Exec Command Option&lt;/h2&gt;
Here is the script we'd like to execute to automatically update our Docker containers running in our production or test server when a new release is made in the GitHub project.
&lt;pre&gt;$cat update-docker.sh 
#!/bin/bash

git pull
docker-compose up -d
&lt;/pre&gt;

&lt;p&gt;Let's kill our SocketXP agent and re-run it with the two new arguments: "filter-rules.json" file and the "update-docker.sh" script file, as shown below.&lt;/p&gt;

&lt;pre&gt;socketxp relay http://localhost:8080 --exec update-docker.sh --filter filter-rules.json

Connected.
Public URL -&amp;gt; https://webhook.socketxp.com/ganeshvelrajan-1awy5t0h
&lt;/pre&gt;

&lt;p&gt;Note that the SocketXP Webhook Public URL has not changed despite killing and re-executing the command. This is because we are requesting a public URL for a webhook relay service again and that too for the same local service endpoints (&lt;a href="http://localhost:8080"&gt;http://localhost:8080&lt;/a&gt;). This nice feature of SocektXP saves us from updating the GitHub Webhook URL settings again.&lt;/p&gt;

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

&lt;p&gt;Now that the CD pipeline is all set, let's upgrade our NodeJS web app and release a version 2.0 of the artifact. We also need to update the docker-compose.yml file to reflect the updated app version.&lt;/p&gt;

&lt;h3&gt;App Upgrade&lt;/h3&gt;

&lt;p&gt;Here is a new version of our app (for the sake of this demo, we have simply updated the version string printed to 2.0).&lt;/p&gt;

&lt;pre&gt;$cat http-server.js 
var http = require('http');
var port = 8080
var handleRequest = function(request, response) {
  console.log('Received HTTP request for URL: ' + request.url);
  response.writeHead(200);
  response.end('Hello World!, v2.0');
};
var server = http.createServer(handleRequest);
server.listen(port);
&lt;/pre&gt;

&lt;h3&gt;Build Push New App Container&lt;/h3&gt;

&lt;p&gt;Build a new docker container containing this new version of our app.&lt;/p&gt;

&lt;pre&gt;$docker build -t gvelrajan/http-server:v2.0 .
Sending build context to Docker daemon  69.63kB
Step 1/7 : FROM alpine:latest
 ---&amp;gt; f70734b6a266
Step 2/7 : RUN apk update &amp;amp;&amp;amp; apk add nodejs
...
...
Successfully tagged gvelrajan/http-server:v2.0
&lt;/pre&gt;

&lt;p&gt;Push the docker image to DockerHub.&lt;/p&gt;

&lt;pre&gt;$docker push gvelrajan/http-server:v2.0
The push refers to repository [docker.io/gvelrajan/http-server]
4a303822279a: Pushed 
947da554eff8: Layer already exists 
cc403a71dcfb: Layer already exists 
3e207b409db3: Layer already exists 
v2.0: digest: sha256:2a9ee82f76758758c77659260091380b20e3b3d095efdc6480d66e47c5842476 size: 1154
&lt;/pre&gt;

&lt;p&gt;Update the docker-compose file with the new docker image version.&lt;/p&gt;

&lt;pre&gt;$cat docker-compose.yml 
version: '3'
services:
  web:
    image: "gvelrajan/http-server:v2.0"
    ports:
      - "8080:8080"
&lt;/pre&gt;

&lt;h3&gt;Git Commit and Release Webhook&lt;/h3&gt;

&lt;p&gt;Perform git commit and push the changes to the GitHub repository. Create new release version  tag "version 2.0" for your project in GitHub.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--epow5U5u--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/i/s6x31dvmwt32c03f96v6.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--epow5U5u--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/i/s6x31dvmwt32c03f96v6.png" alt="Alt Text" width="800" height="652"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This event will make GitHub trigger a webhook to SocketXP agent.&lt;/p&gt;

&lt;h3&gt;Verify Webhook Received&lt;/h3&gt;

&lt;p&gt;Check the console where SocketXP agent is running. It should have received the webhook from GitHub and applied the filters on it.&lt;/p&gt;

&lt;pre&gt;$ socketxp relay http://localhost:8080 --exec update-docker.sh --filter filter-rules.json

Connected.
Public URL -&amp;gt; https://webhook.socketxp.com/ganeshvelrajan-1awy5t0h

Webhook received:
POST / HTTP/1.1
Host: webhook.socketxp.com
Accept: */*
content-type: application/json
User-Agent: GitHub-Hookshot/e509757
X-GitHub-Delivery: fa44ca8e-bd31-11ea-9def-3e0cd2844448
X-GitHub-Event: push
X-Hub-Signature: sha1=d32c79c8de3282e07400711c4e7d3d6542ef79eb

{
  &lt;b&gt;"ref": "refs/tags/2.0",&lt;/b&gt;
  "before": "0000000000000000000000000000000000000000",
  "after": "b5595d43b2c681257e0bae638f9de814df968901",
  "repository": {
    "id": 276817731,
    "node_id": "MDEwOlJlcG9zaXRvcnkyNzY4MTc3MzE=",
    "name": "docker-compose-autoupdate-on-github-webhook",
    "full_name": "socketxp-com/docker-compose-autoupdate-on-github-webhook",
    "private": false,
    ...
    ...
}

&lt;b&gt;#Rule: Webhook signature matched.
#Rule: ref in payload matched.
All rules matched.

Executing command: [update-docker.sh]&lt;/b&gt;
...
...
&lt;/pre&gt;

&lt;p&gt;Check if the docker container has been upgraded and running version 2.0.&lt;/p&gt;

&lt;pre&gt;$docker ps
CONTAINER ID        IMAGE                        COMMAND                 CREATED              STATUS              PORTS                    NAMES
e7ef0e98cd45        gvelrajan/http-server:v2.0   "node http-server.js"   About a minute ago   Up About a minute   0.0.0.0:8080-&amp;gt;8080/tcp   docker-compose-autoupdate-on-github-webhook_web_1_64dc034e55ac
&lt;/pre&gt;

&lt;h3&gt;Verify the upgraded app&lt;/h3&gt;

&lt;p&gt;Curl the web service and verify if the app has been upgraded.&lt;/p&gt;

&lt;pre&gt;$curl http://localhost:8080
&lt;b&gt;Hello World!, v2.0&lt;/b&gt;
&lt;/pre&gt;

&lt;p&gt;Our web app prints "v2.0", denoting that it got updated, automatically!&lt;/p&gt;

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

&lt;p&gt;Setting up Docker Compose to auto deploy on GitHub push or release webhook notification is a great way to set up Continuous Deployment(CD) pipeline. The challenge is in receiving, processing and filtering GitHub webhooks in the production servers or in the internal test servers. &lt;br&gt;
&lt;br&gt;&lt;a href="https://www.socketxp.com"&gt;SocketXP&lt;/a&gt; is a great tool to receive, store, forward, filter and take actions based on webhooks. SocketXP Webhook Relay Service takes care of bulk of the work involved in setting up an automated CD pipeline. So that, developers can focus on their core work, while leaving the rest to SocketXP. &lt;/p&gt;

&lt;p&gt;Moreover, SocketXP has a free tier for developers. And our paid plans start at just $1.99/month.&lt;/p&gt;

&lt;p&gt;&lt;b&gt;This article was originally published at:&lt;br&gt;
&lt;a href="https://www.socketxp.com/webhookrelay/docker-compose-auto-update-github-webhook/"&gt;&lt;/a&gt;&lt;a href="https://www.socketxp.com/webhookrelay/docker-compose-auto-update-github-webhook"&gt;https://www.socketxp.com/webhookrelay/docker-compose-auto-update-github-webhook&lt;/a&gt;&lt;/b&gt;&lt;/p&gt;

</description>
    </item>
    <item>
      <title>How to receive Stripe webhooks on your localhost for development and testing</title>
      <dc:creator>gvelrajan</dc:creator>
      <pubDate>Fri, 26 Jun 2020 06:26:51 +0000</pubDate>
      <link>https://dev.to/gvelrajan/how-to-receive-stripe-webhooks-on-your-localhost-for-development-and-testing-42o8</link>
      <guid>https://dev.to/gvelrajan/how-to-receive-stripe-webhooks-on-your-localhost-for-development-and-testing-42o8</guid>
      <description>&lt;p&gt;Testing Stripe webhooks locally on your localhost machine is easy as long as you have the right set of tools to create a publicly reachable URL for your localhost app.  In this article, I'll demonstrate how to receive and test stripe webhooks locally on your localhost using a simple demo app.&lt;/p&gt;

&lt;h1&gt;What is Stripe Webhook&lt;/h1&gt;

&lt;p&gt;Stripe is one of the major online payment gateway and is a great alternative to paypal. It is a preferred choice for SaaS, e-commerce businesses as well as developers like us. Stripe is popular because it has an easy to use APIs, SDKs in many different programming languages(Ruby, NodeJS, Go, Python, Java etc.) and excellent documentation.&lt;/p&gt;

&lt;p&gt;Stripe, like other online payment platforms, utilizes webhooks to inform the seller’s application about customers, product subscriptions, payment cards and other events occuring in the Stripe payment processing system. Receiving and processing Stripe webhooks are critical for building subscription (recurring payments) based payment gateway application where your backend system needs to track subscription status,&lt;/p&gt;

&lt;h2&gt;What is the problem&lt;/h2&gt;

&lt;p&gt;While it is easy to receive and process Stripe webhooks in production systems (because production systems are mostly customer facing public servers with public IPs), it is extremely challenging to receive and process Stripe webhooks on your local machine during development and testing. Your development and test machines are present in the local network.  Your payment gateway application under development runs on your localhost at some port 8080.  Stripe online cannot reach your localhost app.&lt;/p&gt;

&lt;p&gt;In this article, I’ll demonstrate how to receive and test Stripe webhooks locally on a laptop using a demo application running on a localhost network.&lt;/p&gt;

&lt;h2&gt;What you’ll learn from this article:&lt;/h2&gt;

&lt;ul&gt;
    &lt;li&gt;Build a simple application to receive and process Stripe webhooks for subscription change events.&lt;/li&gt;
    &lt;li&gt;We will use SocketXP webhook proxy service to relay Stripe webhooks to the demo app run locally&lt;/li&gt;
    &lt;li&gt;We will use Stripe’s webhooks testings dashboard to simulate subscription change events.&lt;/li&gt;
    &lt;li&gt;We will use the SocketXP’s webhooks dashboard to monitor and replay the cached webhooks as they pass through the reverse proxy tunnel.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;Before we get started&lt;/h2&gt;

&lt;p&gt;Here are some of the prerequisites for this demo.&lt;/p&gt;

&lt;ul&gt;
    &lt;li&gt;Stripe account. You can register at &lt;a href="https://dashboard.stripe.com/register" rel="noopener"&gt;&lt;strong&gt;https://dashboard.stripe.com/register&lt;/strong&gt;&lt;/a&gt;.&lt;/li&gt;
    &lt;li&gt;SocketXP account. You can register at&lt;strong&gt; &lt;a href="https://portal.socketxp.com" rel="noopener"&gt;https://portal.socketxp.com&lt;/a&gt;&lt;/strong&gt;
&lt;/li&gt;
    &lt;li&gt;SocketXP agent installation instructions can be found here.&lt;/li&gt;
    &lt;li&gt;And ofcourse, Golang installed on your system to try the Go app.  Install it from &lt;a href="https://golang.org/doc/install/source" rel="noopener"&gt;&lt;strong&gt;https://golang.org/doc/install/source&lt;/strong&gt;&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--62RorUzN--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/i/twtzw510m1ut10wtbmx7.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--62RorUzN--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/i/twtzw510m1ut10wtbmx7.png" alt="Alt Text" width="800" height="600"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;The demo application&lt;/h2&gt;

&lt;p&gt;Our demo application is written Go and it simply does the following:&lt;/p&gt;

&lt;ul&gt;
    &lt;li&gt;The app listens on localhost port 8080 and handles any incoming HTTP requests for the subdirectory path “/stripe”.&lt;/li&gt;
    &lt;li&gt;It first verifies the signature of the Stripe webhook notification using the Stripe library method “webhook.ConstructEvent()” to validate the authenticity of the webhook source. For this you need to set an environmental variable named “STRIPE_SECRET” with your stripe secret retrieved from the Stripe Webhooks Dashboard.&lt;/li&gt;
    &lt;li&gt;It processes 3 different Stripe webhook events related to customer subscription.&lt;/li&gt;
    &lt;li&gt;It prints select details from the webhooks received such as CustomerID, Quantity and Status of the subscription.&lt;/li&gt;
    &lt;li&gt;It throws an error if the select details are missing in the webhooks received.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Download the demo application from GitHub: &lt;a href="https://github.com/socketxp-com/stripe-webhook-demo" rel="noopener"&gt;&lt;strong&gt;&lt;a href="https://github.com/socketxp-com/stripe-webhook-demo"&gt;https://github.com/socketxp-com/stripe-webhook-demo&lt;/a&gt;&lt;/strong&gt;&lt;/a&gt;&lt;/p&gt;

&lt;pre&gt;package main

import (
    "fmt"
    "io/ioutil"
    "log"
    "net/http"
    "os"

    "github.com/stripe/stripe-go/webhook"
)

// application server port 
const port = ":8080"

func main() {
    secret := os.Getenv("STRIPE_SECRET")
    if secret == "" {
        fmt.Println("Required STRIPE_SECRET env variable is missing")
        os.Exit(1)
    }

    // incoming stripe webhook handler
    http.HandleFunc("/stripe", func(resp http.ResponseWriter, req *http.Request) {
        body, err := ioutil.ReadAll(req.Body)
        if err != nil {
            resp.WriteHeader(http.StatusBadRequest)
            return
        }

        // validating signature
        event, err := webhook.ConstructEvent(body, req.Header.Get("Stripe-Signature"), secret)
        if err != nil {
            resp.WriteHeader(http.StatusBadRequest)
            fmt.Printf("Failed to validate signature: %s", err)
            return
        }

        switch event.Type {
        case "customer.subscription.created":
            // subscription create event
            customerID, ok := event.Data.Object["customer"].(string)
            if !ok {
                fmt.Println("customer key not found in event.Data.Object")
                return
            }

            subStatus, ok := event.Data.Object["status"].(string)
            if !ok {
                fmt.Println("status key not found in event.Data.Object")
                return
            }

            quantity, ok := event.Data.Object["quantity"]
            if !ok {
                fmt.Println("quantity key not found in event.Data.Object")
                return
            }

            fmt.Printf("customer %s subscription created, quantity (%f), current status: %s \n", customerID, quantity, subStatus)

        case "customer.subscription.updated":
            // subscription update event
            customerID, ok := event.Data.Object["customer"].(string)
            if !ok {
                fmt.Println("customer key not found in event.Data.Object")
                return
            }

            subStatus, ok := event.Data.Object["status"].(string)
            if !ok {
                fmt.Println("status key not found in event.Data.Object")
                return
            }

            quantity, ok := event.Data.Object["quantity"]
            if !ok {
                fmt.Println("quantity key not found in event.Data.Object")
                return
            }

            fmt.Printf("customer %s subscription updated, quantity(%f), current status: %s \n", customerID, quantity, subStatus)
        case "customer.subscription.deleted":
            // subscription deleted event 
            customerID, ok := event.Data.Object["customer"].(string)
            if !ok {
                fmt.Println("customer key not found in event.Data.Object")
                return
            }

            subStatus, ok := event.Data.Object["status"].(string)
            if !ok {
                fmt.Println("status key not found in event.Data.Object")
                return
            }

            quantity, ok := event.Data.Object["quantity"]
            if !ok {
                fmt.Println("quantity key not found in event.Data.Object")
                return
            }

            fmt.Printf("customer %s subscription deleted, quantity(%f), current status: %s \n", customerID, quantity, subStatus)
        default:
            fmt.Printf("Unknown event type received: %s\n", event.Type)
        }
    
    })

    fmt.Printf("Listening for Stripe webhooks on http://localhost%s/stripe \n", port)
    // starting the http server
    log.Fatal(http.ListenAndServe(port, nil))

}
&lt;/pre&gt;

&lt;h2&gt;Downloading and executing the demo application:&lt;/h2&gt;

&lt;p&gt;Assuming that you have already installed Golang on your machine, execute the below commands to download, set the STRIPE_SECRET environmental variable and run the demo application.&lt;/p&gt;

&lt;pre&gt;$ git clone https://github.com/socketxp-com/stripe-webhook-demo.git
$ ls
stripe-webhook-demo
$ cd stripe-webhook-demo/
$ ls
README.md main.go
$ export STRIPE_SECRET=”whsec_…”
$ go run main.go
&lt;/pre&gt;

&lt;p&gt;The demo app listens on “localhost:8080”. We cannot use this local address for registering with Stripe to receive webhooks for development and testing purposes. We need a public IP address or domain name to receive Stripe webhooks. And that’s where the SocketXP webhooks proxy and relay service comes in handy.&lt;/p&gt;

&lt;h2&gt;What is SocketXP&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://www.socketxp.com/how-it-works/"&gt;SocketXP&lt;/a&gt; is a reverse proxy tunneling service that relays webhook notifications from online web services such as Stripe, Paypal, GitHub, DockerHub etc to applications running in localhost network behind NAT and Firewall.&lt;/p&gt;

&lt;p&gt;SocketXP is a freemium SaaS service that significantly reduces the development and testing cycle for software teams, resulting in cost savings.&lt;/p&gt;

&lt;h3&gt;How SocketXP webhook proxy and relay service works&lt;/h3&gt;

&lt;p&gt;Install the SocketXP agent on your localhost machine where your app(webhook receiver) is developed and tested.  It could be installed on your laptop or your office LAN server.  The SocketXP agent creates a secure SSL/TLS tunnel to the SocketXP Cloud Gateway.  The SocketXP Cloud Gateway creates a unique secure (HTTPS) public endpoint for each user.  The user can use the SocketXP public endpoint (URL) to register with online webhook sender applications such as Stripe, Paypal etc.&lt;/p&gt;

&lt;p&gt;When the webhook sender sends a webhook message on the SocketXP public endpoint(URL), SocketXP Cloud Gateway will validate the URL and then forward the webhook to the corresponding registered user's SocketXP agent via a secure (SSL/TLS) tunnel.  The SocketXP agent would in turn forward the webhook message to the receiver application running in the localhost.  Learn more about &lt;a href="https://www.socketxp.com/how-it-works/" rel="noopener"&gt;&lt;strong&gt;how SocketXP solution works here&lt;/strong&gt;&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;SocketXP Cloud Gateway also caches the webhooks locally for your auditing and analysis needs.  Secondly, and more importantly, you could resend failed webhook notifications from the SocketXP dashboard without requesting the sender application to resend the webhook.  This feature is extremely useful during development and testing cycle.&lt;/p&gt;

&lt;h3&gt;Download Install and Login&lt;/h3&gt;

&lt;p&gt;Download and install the SocketXP agent for your OS version and Platform, and authenticate the SocketXP agent to the SocketXP Cloud Gateway by following the instructions &lt;a href="https://www.socketxp.com/download/" rel="noopener"&gt;&lt;strong&gt;here&lt;/strong&gt;&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;Create SocketXP public webhook relay endpoint&lt;/h3&gt;

&lt;pre&gt;$socketxp relay http://localhost:8080/stripe

Connected.
Public URL -&amp;gt; https://webhook.socketxp.com/test-user-gmail-com-45803
&lt;/pre&gt;

&lt;p&gt;Use this SocketXP public webhook endpoint (URL) to register with Stripe Webhook Testing Dashboard, explained in the next section.&lt;/p&gt;

&lt;h2&gt;Sending test webhooks from Stripe dasboard&lt;/h2&gt;

&lt;p&gt;Login to your Stripe account&lt;/p&gt;

&lt;p&gt;Toggle the “view test data” button on the side navigation bar to put Stripe on a test mode.&lt;/p&gt;

&lt;p&gt;Select the “webhooks” under the head “Developers” on the side navigation bar or go to &lt;a href="https://dashboard.stripe.com/test/webhooks"&gt;https://dashboard.stripe.com/test/webhooks&lt;/a&gt;&lt;/p&gt;

&lt;p&gt; &lt;/p&gt;

&lt;p&gt;[caption id="attachment_908" align="aligncenter" width="1920"]&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--9TrszWAa--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://www.socketxp.com/wp-content/uploads/2020/05/Testing-Stripe-Webhooks-Locally-on-Localhost.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--9TrszWAa--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://www.socketxp.com/wp-content/uploads/2020/05/Testing-Stripe-Webhooks-Locally-on-Localhost.png" alt="Testing Stripe webhooks locally stripe webhooks localhost" width="800" height="410"&gt;&lt;/a&gt; Stripe Webhooks Testing Dashboard[/caption]&lt;/p&gt;

&lt;p&gt; &lt;/p&gt;

&lt;p&gt;Click the “Add endpoints” button on the right hand side window.&lt;/p&gt;

&lt;p&gt;Add the SocketXP public webhook URL to the “Endpoint URL” text box. Choose the Stripe webhook events “customer.subscription.created”, “customer.subscription.updated”, “customer.subscription.deleted” from the “Events to send” drop down menu box right below it. Finally, click the “Add endpoint” button below to save the endpoint.&lt;/p&gt;

&lt;p&gt;Now click open the endpoint you just added. And click the “Send test webhook” button on the top. Choose the Stripe webhook events, you wish to send and click the “Send test webhook” button.&lt;/p&gt;

&lt;p&gt;Our demo app should receive webhook events from the Stripe webhook dashboard.&lt;/p&gt;

&lt;h2&gt;Demo app output:&lt;/h2&gt;

&lt;p&gt;The demo app receives webhooks from the SocketXP agent running locally on the same machine.&lt;/p&gt;

&lt;pre&gt;$go run main.go
Listening for Stripe webhooks on http://localhost:8080/stripe
customer cus_00000000000000 subscription created, quantity(1.000000), current status: active
customer cus_00000000000000 subscription updated, quantity(1.000000), current status: active
customer cus_00000000000000 subscription deleted, quantity(1.000000), current status: canceled
&lt;/pre&gt;

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

&lt;p&gt;Stripe is a great payment gateway for developers to integrate because of its easy to use APIs and SDKs. Developing, integrating and testing your backend application with Stripe webhooks dashboard on your local machine could be a nightmare.  SocketXP webhook proxy service and the record/replay option will significantly reduce the development and testing time (and ofcourse, the cost) for your software team.&lt;/p&gt;

&lt;p&gt;&lt;b&gt;This article was originally published at:&lt;br&gt;
&lt;a href="https://www.socketxp.com/webhookrelay/testing-stripe-webhooks-locally-stripe-webhooks-localhost/"&gt;&lt;/a&gt;&lt;a href="https://www.socketxp.com/webhookrelay/testing-stripe-webhooks-locally-stripe-webhooks-localhost/"&gt;https://www.socketxp.com/webhookrelay/testing-stripe-webhooks-locally-stripe-webhooks-localhost/&lt;/a&gt;&lt;/b&gt;&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Auto Deploy from GitHub to Local Server on Git Push</title>
      <dc:creator>gvelrajan</dc:creator>
      <pubDate>Fri, 26 Jun 2020 06:12:55 +0000</pubDate>
      <link>https://dev.to/gvelrajan/auto-deploy-from-github-to-local-server-on-git-push-mp5</link>
      <guid>https://dev.to/gvelrajan/auto-deploy-from-github-to-local-server-on-git-push-mp5</guid>
      <description>&lt;p&gt;As developers (oh yeah, as devops guys), it's a no-brainer to automate our workflows to make life simple and easy for us. In this article, I'll demonstrate how to automatically deploy a nodejs web app from GitHub to a production or test server on git push. You can follow the same instructions to deploy any application written in any language.&lt;/p&gt;

&lt;h2&gt;Tools used in this demo&lt;/h2&gt;

&lt;p&gt;We use quite a few tools in this demo. Each one has a specific role to play in the Continuous Deployment(CD) pipeline we are about to setup. Each of these tools are briefly explained below.&lt;/p&gt;

&lt;h3&gt;Nodemon&lt;/h3&gt;

&lt;p&gt;Monitors any changes in your node.js application and automatically restarts the server. Though Nodemon is typically used in development for quick re-spins, we'll use it in production in this demo to simply explain you the overall concept.&lt;/p&gt;

&lt;h3&gt;Webhook&lt;/h3&gt;

&lt;p&gt;Incoming webhooks handler which can execute shell commands.&lt;/p&gt;

&lt;h3&gt;SocketXP&lt;/h3&gt;

&lt;p&gt;Enables us to receive webhooks from the internet and relay it into your local network without exposing the app to the internet. SocketXP eliminates the need to own a public IP.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--nKefV6PT--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/i/8cxc9v6gqlzwx5oxwtti.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--nKefV6PT--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/i/8cxc9v6gqlzwx5oxwtti.png" alt="Alt Text" width="800" height="600"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;Demo app&lt;/h3&gt;

&lt;p&gt;We'll use the following simple nodejs web application for this demo.&lt;/p&gt;

&lt;pre&gt;var http = require('http');
var port = 8080
var handleRequest = function(request, response) {
  console.log('Received HTTP request for URL: ' + request.url);
  response.writeHead(200);
  response.end('Hello World!, v1.0');
};
var server = http.createServer(handleRequest);
server.listen(port);
&lt;/pre&gt;

&lt;p&gt;You can find the source code used in this demo at the following github repo:&lt;br&gt;
&lt;a href="https://github.com/socketxp-com/webhook-autoupdate"&gt;&lt;/a&gt;&lt;a href="https://github.com/socketxp-com/webhook-autoupdate"&gt;https://github.com/socketxp-com/webhook-autoupdate&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;# Git clone the demo app&lt;/h3&gt;

&lt;p&gt;First clone the demo app from GitHub.&lt;/p&gt;

&lt;pre&gt;$ git clone https://github.com/socketxp-com/webhook-autoupdate.git
&lt;/pre&gt;

&lt;h3&gt;# Install Nodemon&lt;/h3&gt;

&lt;p&gt;Change the working directory to the &lt;b&gt;"webhook-autoupdate"&lt;/b&gt; git folder you just cloned above. Install nodemon globally and run it.&lt;/p&gt;

&lt;pre&gt;$ cd webhook-autoupdate

$ npm install -g nodemon
$nodemon
[nodemon] 2.0.4
[nodemon] to restart at any time, enter `rs`
[nodemon] watching path(s): *.*
[nodemon] watching extensions: js,mjs,json
[nodemon] starting `node http-server.js`
&lt;/pre&gt;

&lt;h3&gt;Curl the demo web app&lt;/h3&gt;

&lt;p&gt;Access the NodeJS web app running at &lt;a href="http://localhost:8080"&gt;http://localhost:8080&lt;/a&gt; using curl.&lt;/p&gt;

&lt;pre&gt;$curl http://localhost:8080
Hello World!, v1.0
&lt;/pre&gt;

&lt;h3&gt;# Install Webhook app&lt;/h3&gt;

&lt;p&gt;To handle push notifications (or webhooks) from github (or any webhook sender application for that matter), you don't need to implement a webhook handler yourself. There are apps available to offload the job. One such app is &lt;a href="https://github.com/adnanh/webhook"&gt;&lt;b&gt;Webhook app&lt;/b&gt;&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Using the Webhook app easily create HTTP endpoints (webhooks handler) on your server, which you can use to execute configured commands. Webhook app also allows you to specify rules which must be satisfied in order for any hook to be triggered.&lt;/p&gt;

&lt;p&gt;Download the Webhook app (choose one appropriate for your OS and Platform) from the &lt;a href="https://github.com/adnanh/webhook/releases"&gt;&lt;b&gt;github repo release folder&lt;/b&gt;&lt;/a&gt;&lt;/p&gt;

&lt;pre&gt;$wget https://github.com/adnanh/webhook/releases/download/2.7.0/webhook-darwin-amd64.tar.gz
$ls
webhook-darwin-amd64.tar.gz
$tar -xvf webhook-darwin-amd64.tar.gz 
x webhook-darwin-amd64/
x webhook-darwin-amd64/webhook
$ls
webhook-darwin-amd64        webhook-darwin-amd64.tar.gz
$cd webhook-darwin-amd64
$ls
webhook
$
&lt;/pre&gt;

&lt;p&gt;You'll find a "hooks.json" file in the &lt;b&gt;"webhook-autoupdate"&lt;/b&gt; GitHub repository that you cloned in the previous section. Update the hooks.json file with the correct directory names and secret value, as shown by the marked lines below.&lt;/p&gt;

&lt;pre&gt;[
  {
    "id": "webhook",
    "execute-command": "/Users/gannygans/webhook-autoupdate/update-nodejs.sh",   // &amp;lt;&amp;lt;&amp;lt;=== Update this field to your directory path
    "command-working-directory": "/Users/gannygans/webhook-autoupdate",    // &amp;lt;&amp;lt;&amp;lt;=== Update this field to your directory path
    "response-message": "I got the payload!",
    "response-headers":
    [
      {
        "name": "Access-Control-Allow-Origin",
        "value": "*"
      }
    ],
    "pass-arguments-to-command":
    [
      {
        "source": "payload",
        "name": "head_commit.id"
      },
      {
        "source": "payload",
        "name": "pusher.name"
      },
      {
        "source": "payload",
        "name": "pusher.email"
      }
    ],
    "trigger-rule":
    {
      "and":
      [
        {
          "match":
          {
            "type": "payload-hash-sha1",
            "secret": "adsFgGdf1T23423",    // &amp;lt;&amp;lt;&amp;lt;&amp;lt;==== Update the secret 
            "parameter":
            {
              "source": "header",
              "name": "X-Hub-Signature"
            }
          }
        },
        {
          "match":
          {
            "type": "value",
            "value": "refs/heads/master",
            "parameter":
            {
              "source": "payload",
              "name": "ref"
            }
          }
        }
      ]
    }
  }
]
&lt;/pre&gt;

&lt;p&gt;Use this hooks.json file to kickstart the webhook app.&lt;/p&gt;

&lt;pre&gt;$./webhook -hooks hooks.json -verbose
[webhook] 2020/06/25 16:27:42 version 2.7.0 starting
[webhook] 2020/06/25 16:27:42 setting up os signal watcher
[webhook] 2020/06/25 16:27:42 attempting to load hooks from hooks.json
[webhook] 2020/06/25 16:27:42 os signal watcher ready
[webhook] 2020/06/25 16:27:42 found 1 hook(s) in file
[webhook] 2020/06/25 16:27:42   loaded: webhook
[webhook] 2020/06/25 16:27:42 serving hooks on http://0.0.0.0:9000/hooks/{id}
&lt;/pre&gt;

&lt;p&gt;Note: The above webhook URL "&lt;a href="http://0.0.0.0:9000/hooks/%7Bid%7D"&gt;http://0.0.0.0:9000/hooks/{id}&lt;/a&gt;" is a localhost url. Github cannot send notifications to this IP address because it is not a publicly reachable IP address. Github needs a publicly reachable public URL to send push notifications.&lt;/p&gt;

&lt;p&gt;This is where SocketXP solution comes in handy. We can use the SocketXP Secure Reverse Proxy Tunneling service to relay webhooks notifications from Github to the localhost Webhook app.&lt;/p&gt;

&lt;h3&gt;# Install SocketXP agent&lt;/h3&gt;

&lt;p&gt;Download and install SocketXP agent on your system following the instructions here - &lt;a href="https://www.socketxp.com/download/"&gt;SocketXP Downaload and Install&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;After SocketXP agent is installed, request the agent to relay the github webhook to your local webhook URL as shown below.&lt;/p&gt;

&lt;pre&gt;$ socketxp relay http://0.0.0.0:9000/hooks/webhook

Connected.
Public URL -&amp;gt; https://webhook.socketxp.com/ganeshvelrajan-0er32gfj
&lt;/pre&gt;

&lt;p&gt;Now copy the above SocketXP Public URL and use it to update the webhook settings in the Github page of your project repository as shown below. Also make sure you select the payload content type to "applicatin/json" in the dropdown box. Save the changes.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--UxMzmUzJ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://www.socketxp.com/wp-content/uploads/2020/06/Auto-Deploy-Github-to-Server-.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--UxMzmUzJ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://www.socketxp.com/wp-content/uploads/2020/06/Auto-Deploy-Github-to-Server-.png" alt="Automatically Deploy from GitHub to Server using Webhook" width="800" height="570"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;Begin Auto Deploy Demo&lt;/h2&gt;

&lt;p&gt;Let's begin the demo by committing a code change into Github.&lt;/p&gt;

&lt;h3&gt;Git commit and push&lt;/h3&gt;

&lt;p&gt;Commit a code change into your Github project. I have bumped up the version string in my http-server.js" to version 2.0 and committed the code changes.&lt;/p&gt;

&lt;pre&gt;$git commit http-server.js -m "minor fix"
[master cae0d29] minor fix
 1 file changed, 1 insertion(+), 1 deletion(-)
$git push
Counting objects: 3, done.
Delta compression using up to 8 threads.
Compressing objects: 100% (3/3), done.
Writing objects: 100% (3/3), 286 bytes | 286.00 KiB/s, done.
Total 3 (delta 2), reused 0 (delta 0)
remote: Resolving deltas: 100% (2/2), completed with 2 local objects.
To https://github.com/socketxp-com/webhook-autoupdate.git
   f4f1516..cae0d29  master -&amp;gt; master
&lt;/pre&gt;

&lt;h3&gt;SocketXP webhook relay agent&lt;/h3&gt;

&lt;p&gt;Check if the SocketXP agent has received the webhook notifications from Github.&lt;/p&gt;

&lt;pre&gt;Webhook received:
POST /hooks/webhook HTTP/1.1
Host: webhook.socketxp.com
Accept: */*
Accept-Encoding: gzip
Content-Length: 8077
Content-Type: application/json
User-Agent: GitHub-Hookshot/3ea2330
X-Github-Delivery: b55dd9f6-b6d3-11ea-9b25-2831f872cb2c
X-Github-Event: push
X-Hub-Signature: sha1=43b9f9114ecf5c3da6e306976f95766f52c6bdd9

{"ref":"refs/heads/master","before":"714706d5f6f411581ec7abf1653c4a1e3cd6d53b","after":"49d0ec0d1310917338baf1dcda5e3bc99b2f2644","repository":{"id":274867773,"node_id":"MDEwOlJlcG9zaXRvcnkyNzQ4Njc3NzM=","name":"webhook-autoupdate","full_name":"socketxp-com/webhook-autoupdate","private":false,"owner":{"name":"socketxp-com","email":"64076796+socketxp-com@users.noreply.github.com",  ... }

&lt;/pre&gt;

&lt;h3&gt;Check the webhook app&lt;/h3&gt;

&lt;p&gt;Check if the webhook app has received the webhook notification from the SocketXP agent and processed the webhook notification.&lt;/p&gt;

&lt;pre&gt;$./webhook -hooks hooks.json -verbose
[webhook] 2020/06/25 16:27:42 version 2.7.0 starting
[webhook] 2020/06/25 16:27:42 setting up os signal watcher
[webhook] 2020/06/25 16:27:42 attempting to load hooks from hooks.json
[webhook] 2020/06/25 16:27:42 os signal watcher ready
[webhook] 2020/06/25 16:27:42 found 1 hook(s) in file
[webhook] 2020/06/25 16:27:42   loaded: webhook
[webhook] 2020/06/25 16:27:42 serving hooks on http://0.0.0.0:9000/hooks/{id}
&lt;b&gt;[webhook] 2020/06/25 16:35:00 [0fd63b] incoming HTTP POST request from 127.0.0.1:57435
[webhook] 2020/06/25 16:35:00 [0fd63b] webhook got matched
[webhook] 2020/06/25 16:35:00 [0fd63b] webhook hook triggered successfully
[webhook] 2020/06/25 16:35:00 [0fd63b] 200 | 18 B | 531.245µs | webhook.socketxp.com | POST /hooks/webhook
[webhook] 2020/06/25 16:35:00 [0fd63b] executing /Users/gannygans/webhook-autoupdate/update-nodejs.sh (/Users/gannygans/webhook-autoupdate/update-nodejs.sh) with arguments ["/Users/gannygans/webhook-autoupdate/update-nodejs.sh" "49d0ec0d1310917338baf1dcda5e3bc99b2f2644" "socketxp-com" "64076796+socketxp-com@users.noreply.github.com"] and environment [] using /Users/gannygans/webhook-autoupdate as cwd
   057cadf..069d282  master     -&amp;gt; origin/master
Updating 057cadf..069d282
Fast-forward
 http-server.js | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
Current branch master is up to date.

[webhook] 2020/06/25 16:35:02 [0fd63b] command output: Already up to date.
Current branch master is up to date.

[webhook] 2020/06/25 16:35:02 [0fd63b] finished handling webhook&lt;/b&gt;
&lt;/pre&gt;

&lt;h3&gt;Check Nodemon has restarted the web server&lt;/h3&gt;

&lt;pre&gt;$nodemon
[nodemon] 2.0.4
[nodemon] to restart at any time, enter `rs`
[nodemon] watching path(s): *.*
[nodemon] watching extensions: js,mjs,json
&lt;b&gt;[nodemon] starting `node http-server.js`
[nodemon] restarting due to changes...&lt;/b&gt;
&lt;/pre&gt;

&lt;h3&gt;Curl the web server&lt;/h3&gt;

&lt;pre&gt;$curl http://localhost:8080
Hello World!, v2.0
&lt;/pre&gt;

&lt;p&gt;The hello-world application displays "v2.0" in the output, which proves that the auto deployment has worked as we expected.&lt;/p&gt;

&lt;p&gt;That's all folks!&lt;/p&gt;

&lt;p&gt;You can receive webhooks from any online service to your local server using SocketXP. SocketXP eliminates the need to own a public IP address to receive webhook notifications from online services. Moreover, SocketXP has a free-tier for developers.&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Turnkey Solution for Raspberry Pi Remote SSH Access Over the Internet</title>
      <dc:creator>gvelrajan</dc:creator>
      <pubDate>Wed, 24 Jun 2020 06:47:59 +0000</pubDate>
      <link>https://dev.to/gvelrajan/turnkey-solution-from-socketxp-for-raspberry-pi-remote-ssh-access-4jm</link>
      <guid>https://dev.to/gvelrajan/turnkey-solution-from-socketxp-for-raspberry-pi-remote-ssh-access-4jm</guid>
      <description>&lt;p&gt;Imagine managing few thousands of Raspberry Pi devices at your work or at your customer site behind firewall or NAT.  How would you configure, setup, access or even debug them from remote locations?&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.socketxp.com/iot/remote-access-iot-ssh-over-the-internet/"&gt;SocketXP provides turnkey IoT solution&lt;/a&gt; that can bring up hundreds or thousands of RPi devices online for remote SSH connectivity in less than a minute(limited only by your ability to copy paste a command).&lt;/p&gt;

&lt;p&gt;Not just that, it is highly secure (uses SSL/TLS tunneling - a lightweight VPN alternative solution)&lt;/p&gt;

&lt;p&gt;How the SockeXP turnkey solution for Raspberry Pi Remote SSH Access over the Internet&lt;/p&gt;

&lt;p&gt;Just 2 simple steps.&lt;/p&gt;

&lt;h2&gt;Step #1&lt;/h2&gt;

&lt;p&gt;Copy a single command from &lt;a href="https://portal.socketxp.com/#/devices"&gt;SocketXP Portal Page&lt;/a&gt; as shown below.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--RY11yFMP--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/i/o50bddoudspd8rjoe5yq.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--RY11yFMP--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/i/o50bddoudspd8rjoe5yq.png" alt="Alt Text" width="800" height="470"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;b&gt;Note:&lt;/b&gt;  The above command has a unique auth-token assigned just for you and your devices.&lt;/p&gt;

&lt;p&gt;Paste the above command on your Raspberry Pi device terminal.  Paste this command on as many number of devices as you want to bring up for remote connectivity.  Just one command for all your RPi devices.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--KDRiXvHh--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/i/drf6qgi47mai9q5j6mpg.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--KDRiXvHh--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/i/drf6qgi47mai9q5j6mpg.png" alt="Alt Text" width="800" height="553"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;Step #2&lt;/h2&gt;

&lt;p&gt;Check if your device is up and connected on the SocketXP portal page as shown below. &lt;/p&gt;

&lt;p&gt;Click the terminal icon next to your RPi device.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--xGIQT6SB--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/i/nudn1le24zgkfmqu76y3.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--xGIQT6SB--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/i/nudn1le24zgkfmqu76y3.png" alt="Alt Text" width="800" height="471"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Provide your RPi SSH credentials in the next screen.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--OTTaWgBO--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/i/jfy1nvv4d5r4bhzxsmxb.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--OTTaWgBO--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/i/jfy1nvv4d5r4bhzxsmxb.png" alt="Alt Text" width="800" height="470"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Boom... and there you are, now inside your RPi SSH shell.  &lt;/p&gt;

&lt;p&gt;Now type any command in the shell.  Say for example "htop".&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--KP45643Z--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/i/xsfq61axv065qlq086kn.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--KP45643Z--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/i/xsfq61axv065qlq086kn.jpg" alt="Alt Text" width="800" height="580"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;How hard was this?  Easy-Peasy isn't it?&lt;/p&gt;

&lt;p&gt;Let me know what you think about this single-touch installation and our SocketXP Raspberry Pi remote SSH connectivity solution in general.&lt;/p&gt;

&lt;p&gt;BTW, did I say that it's completely free for adding upto 4 RPi devices?&lt;/p&gt;

&lt;p&gt;Got 5 or more devices? SocketXP service is just 20 Cents per device for one full month of remote connectivity ?  And that too backed by a 14-day money back guarantee!!  &lt;/p&gt;

&lt;p&gt;Read more about the full solution here:&lt;br&gt;
&lt;a href="https://www.socketxp.com/iot/remote-access-iot-ssh-over-the-internet/"&gt;&lt;b&gt;&lt;a href="https://www.socketxp.com/iot/remote-access-iot-ssh-over-the-internet/"&gt;https://www.socketxp.com/iot/remote-access-iot-ssh-over-the-internet/&lt;/a&gt;&lt;/b&gt;&lt;/a&gt;&lt;/p&gt;

</description>
      <category>raspberrypiremoteassh</category>
      <category>iotremotessh</category>
      <category>iotremoteconnect</category>
      <category>raspberrypifleetmanagement</category>
    </item>
  </channel>
</rss>
