Automate certificate collection from Kubernetes secret and Update in Multiple VM’s By using python

Ritesh Singh Maurya
Fournine Cloud
Published in
5 min readNov 15, 2022

--

A person sitting relaxed while a. robot is working for him

What is an SSL certificate?

An SSL certificate is a digital certificate that authenticates a website’s identity and enables an encrypted connection. SSL stands for Secure Sockets Layer, a security protocol that creates an encrypted link between a web server and a web browser.

STEP-1

How to install Gcloud?

We install gcloud by following below given steps

1st. Run this command for download gcloud sdk.

curl -O https://dl.google.com/dl/cloudsdk/channels/rapid/downloads/google-cloud-cli-408.0.0-linux-x86_64.tar.gz

2nd. Unzip downloaded package

tar -xf google-cloud-cli-408.0.0-linux-x86.tar.gz

3rd. Just run install.sh file for installing

./google-cloud-sdk/install.sh

4th. To initialize the gcloud CLI, run gcloud init

./google-cloud-sdk/bin/gcloud init

After all this steps you need to authenticate with GCP by your credentials.

STEP-2

Authenticating with Gcloud.

Simple you need to run below command

gcloud auth login

After setup your gcloud account you have to install Kubernetes and connect with cluster which cluster you have certificates.

STEP-3

Installing Kubectl

You have to run below commands

gcloud components install kubectl

If you want check your kubectl version run below command.

kubectl version

After installing kubectl you have setup your cluster by below commands.

gcloud container clusters get-credentials {cluster_name} --region {region} --project {project}

STEP-4

After setup all things you need to add your kubernets secrets detail and vm’s detail in connection.properties file.

Here below we show how our connection.properties files looks like.

connection.properties file.

#section-1[secret-name-you-need-to-here]host = 127.0.0.1 #you have to add here your vm's hostport = 22 #your portusername = ravikumar #your gcpusernamecpcmd = sudo service httpd status #for checking vm statusreloadservercmd= sudo service nginx restart #need to reload your server after put certificates in there placevmpath = /etc/ssl/certs/app #certifcate path in vm’svmpath_key = /etc/ssl/certs/app #certificate key path in vm’spvtkey =/usr/local/bin/app/sshkey/google_compute_engine #privatekey path we use connect with vm'srenewflag = false #if you want skip this section simple set "False" if want execute this section set value "True"serverurl= ex-google.com #your server domaindayslefttorenew = 30 #add checking condintion in how many days left so you want update certifictesecret_namespace = cert-env #secret namespace#Section-2[secret-name-you-need-to-here]host = 127.0.0.1 #you have to add here your vm's hostport = 22 #your portusername = ravikumar #your gcpusernamecpcmd = sudo service httpd status #for checking vm statusreloadservercmd= sudo service nginx restart #need to reload your server after put certificates in there placevmpath = /etc/ssl/certs/app #certifcate pathvmpath_key = /etc/ssl/certs/app #certificate key pathpvtkey =/usr/local/bin/app/sshkey/google_compute_engine #privatekey we use connect with vm'srenewflag = false #if you want skip this section simple set "False" if want execute this section set value "True"serverurl= ex-google.com #your server domaindayslefttorenew = 30 #add checking condintion in how many days left so you want update certificatesecret_namespace = cert-env #secret namespace

After adding all correct information in data.properties file you need to install few python lib.

pip3 install kubernetespip3 install paramikopip3 install scppip3 install kubeconfigpip3 install pyopenssl

After installing you have to create main.py file.

main.py file

import loggingimport configparserfrom kubernetes import configimport sysfrom vmcertdeployer import loadk8sapi,loadconfig,loadconfigfile,getcertproperties,getcertdetails,getcertandkey,getcertexpdate,executecommands,certdeploylogging.basicConfig(level=logging.INFO,format='%(asctime)s.%(msecs)03d %(levelname)s - %(message)s',datefmt='%Y-%m-%d %H:%M:%S',)config.load_kube_config()config = configparser.ConfigParser()config.read("../config/connection.properties")if len(sys.argv) != 2:logging.info("please provide input parameter <<manual>> or <<auto>>")if((sys.argv[1])=="auto"):for section_name in config.sections():logging.info("**************working on %s certificate*****************" %(section_name)) #section name used for collect cert and key from clustervmhost,vmusername,vmcmd, vmreloadcmd,vmpath, pvtkeypath, renew,servername,days_to_renew,secret_ns,vmpath_key = getcertproperties(section_name)logging.info("Server urls: %s" % (servername)) #servername used for collect endpoint url ssl exp dateif(renew == "true"):namespace,secretname = getcertdetails(section_name,"ADDED",secret_ns)if namespace != None and secretname != None:certdeploy(secretname,namespace,vmhost,vmusername,vmcmd,vmreloadcmd,vmpath,pvtkeypath,servername,days_to_renew,section_name,vmpath_key)else:logging.error("Certificate not available in cluster..")sys.exit(1)else:logging.info("renewal flag is disabled in the properties file")logging.info("***********************************************************\n")

After creating main.py file need to create one more last file vmcertdeployer.py file

vmcertdeployer.py file

import loggingimport paramikoimport configparserfrom scp import SCPClientfrom kubernetes import client, config, watchimport datetimeimport sslimport OpenSSLimport base64import sys#set up a basic logging formatlogging.basicConfig(level=logging.INFO,format='%(asctime)s.%(msecs)03d %(levelname)s - %(message)s',datefmt='%Y-%m-%d %H:%M:%S',)def loadk8sapi():#Get the kubernetes core api and the watcherv1 = client.CoreV1Api()w = watch.Watch()return v1,wdef loadconfig():config.load_kube_config()return configdef loadconfigfile():config = configparser.ConfigParser()try:config.read_file(open("../config/connection.properties", "r"))return configexcept IOError as exception:logging.error(exception)def getcertproperties(cert):config=loadconfigfile()for key,value in config.items(cert):vmhost = config.get(cert, 'host', raw=False)vmusername = config.get(cert,"username",raw=False)vmcmd = config.get(cert,"cpcmd",raw=False)vmreloadcmd = config.get(cert,"reloadservercmd",raw=False)vmpath = config.get(cert,"vmpath",raw=False)pvtkeypath = config.get(cert,"pvtkey",raw=False)renew = config.get(cert,"renewflag",raw=False)servername = config.get(cert,"serverurl",raw=False)days_to_renew = config.get(cert,"dayslefttorenew",raw=False)secret_ns = config.get(cert,"secret_namespace",raw=False)vmpath_key= config.get(cert,"vmpath_key",raw=False)return vmhost, vmusername, vmcmd, vmreloadcmd, vmpath, pvtkeypath, renew, servername, days_to_renew, secret_ns, vmpath_keydef getcertdetails(certname,eventtype,secret_ns):v1,w= loadk8sapi()for event in w.stream(v1.list_namespaced_secret, secret_ns, timeout_seconds=10):if ((event['object'].metadata.name == certname) and  (event['type'] == eventtype)):namespace = event['object'].metadata.namespacesecretname = event['object'].metadata.namereturn namespace,secretnameelse:return None,Nonedef getcertandkey(namespace,secret,section_name):try:v1 = client.CoreV1Api()sec = v1.read_namespaced_secret(section_name,namespace).data #passing here our like secret="kibana.intalto.ruckuswireless.com" and namespace="certs-int"cert=base64.b64decode(sec["tls.crt"])file1 = open(str(section_name)+":ns:"+str(namespace)+".crt", "ab")  # append mode with bite code, create your file name according your requirementfile1.write(cert)file1.close()logging.info("Certificate collected succesfully..")key=base64.b64decode(sec["tls.key"])file2 = open(str(section_name)+":ns:"+str(namespace)+".key", "ab")  # append mode with bite code, create your file name according your requirementfile2.write(key)file2.close()logging.info("Key collected succesfully..")except Exception as e:logging.error(e)return 'error'def getcertexpdate(servername,days_to_renew):try:cert = ssl.get_server_certificate((servername, int(443)))x509 = OpenSSL.crypto.load_certificate(OpenSSL.crypto.FILETYPE_PEM, cert)notbefore_date = datetime.datetime.strptime(x509.get_notBefore().decode('utf-8'), '%Y%m%d%H%M%S%z')notafter_date = datetime.datetime.strptime(x509.get_notAfter().decode('utf-8'), '%Y%m%d%H%M%S%z')delta = notafter_date - datetime.datetime.now(datetime.timezone.utc)expriy_of_ssl="the existing cert validity is notBefore={notbefore} notAfter={notafter}".format(notbefore=str(notbefore_date),notafter=str(notafter_date))logging.info(expriy_of_ssl)logging.info("renew the cert if it is expiring in %s days",days_to_renew)if int(delta.days) > 0:logging.info("number of days left for the cert to expire %d"%delta.days)else:logging.info("certificate already expire please renew..")if int(delta.days) < int(days_to_renew):logging.info("decision to renew is: true")return "true"else:logging.info("decision to renew is: false")return "false"except Exception as e:logging.error(e)return Nonedef executecommands(cpcmd,reloadcmd,sshclient):commands = [cpcmd,reloadcmd]for command in commands:logging.info("Executing %s" % command )stdin , stdout, stderr = sshclient.exec_command(command)def certdeploy(secret,namespace,host,username,vmcmd,vmreloadcmd,vmpath,pvtkey,servername,days_to_renew,section_name,vmpath_key):crtfile = secret+":ns:"+namespace+".crt"keyfile = secret+":ns:"+namespace+".key"to_be_renewed = getcertexpdate(servername,days_to_renew)# to_be_renewed = Noneif (to_be_renewed == None):logging.error("Please check are you able to access url:%s" % servername)logging.info("**************************************************************\n")sys.exit(1)if(to_be_renewed == "true"):check_status=getcertandkey(namespace,servername,section_name)if check_status == 'error':logging.error("Something issue with getcertandkey function please check..")sys.exit(1)else:logging.info("renewing with a new cert as the cert exp date is less than days_to_renew")hostpvtkey = paramiko.RSAKey.from_private_key_file(pvtkey)sshclient = paramiko.SSHClient()sshclient.set_missing_host_key_policy(paramiko.AutoAddPolicy())ssh_clinect_connectivity=sshclient.connect( hostname = host, username = username, pkey = hostpvtkey,timeout=50 )logging.info("connected to the Server")scp = SCPClient(sshclient.get_transport())scp.put(crtfile, remote_path=vmpath)scp.put(keyfile, remote_path=vmpath_key)executecommands(vmcmd,vmreloadcmd,sshclient)scp.close()logging.info("******************************************************************\n")if(to_be_renewed == "false"):logging.info("not renewing the cert as the existing certificate expiry date is greater than defined parameter in properties")logging.info("*****************************************************************\n")

After created all file you need to execute main.py file by using below command and it collect all information from connection.properties file according your information it collect data from cluster and push the cert in vm’s and reload vm service.

python3 main.py auto

And that’s it, job is done.

For more such stroies on automations in DevOps, Do follow us

--

--