Setting up Kubernetes to manage containers on the Google Cloud Platform

These days the pace of innovation in DevOps can leave you feeling like you’re jogging on a treadmill programmed to run faster than Usain Bolt. Mastery requires hours of practice and the last decade in DevOps has not allowed for it. Before gaining 10 years of experience running virtual machines using VmWare in private data-centers, private cloud software like Openstack and Cloudstack came along, and just when you and your team painfully achieved a stable install you were told running virtual machines in public clouds like AWS, GCP, and Azure is the way forward. By the time you got there it was time to switch to containers, and before you can fully appreciate those, server-less functions are on the horizon, but I digress. If you want to know more about server-less functions, see my previous article on AWS Lambda. Instead, this article will focus on running Docker containers inside of a Kubernetes cluster on Google’s Cloud Platform.

Linux Containers, which were recently popularized by Docker need something to help manage them and while there are many choices, Kubernetes the open-sourced container management system from Google is the undisputed king at this time. Given that Kubernetes was started by Google, it should be expected that the easiest way to install it is using Google’s Cloud Platform (GCP). However, Openshift from Redhat also provides a nice batteries included abstraction if you need to get up and running quickly as well as kops.

Pre-Requisites

The main pre-requisites you need for this article is a Google Cloud Platform account and installing the gcloud utility via the SDK.

In addition, you need some form of a computer with Internet connectivity, some typing skills, a brain that can read, and a determination to finish…For now I will give you the benefit of the doubt and assume you have all of these. It is also nice to have your beverage of choice while you do this, a fine tea, ice cold beer, or glass of wine will work, but for Cancer’s sake please skip the sugar.

Here is where I would normally insert a link to facts on sugar and Cancer’s link, but I literally just learned I would be spreading rumors… Fine drink your Kool-Aid, but don’t blame me for your calories.

The Build Out of our Self Healing IRC Server Hosting Containers

I lied dude, IRC is so 1995 and unfortunately, ICQ’s been dead and Slack won’t let me host their sexy chat application with game like spirit and better jokes than Kevin Heart. So…sorry to excite you… but I guess I will fallback to the docs here and install Nginx like us newb’s are supposed to.

Numero Uno (Step 1 dude)

As part of the installation of the gcloud / SDK you should have ran gcloud init, which requires you to login with your Google account via a web browser.

You must log in to continue. Would you like to log in (Y/n)?  Y

Your browser has been opened to visit:

    https://accounts.google.com/o/oauth2/auth?redirect_uri=http%3A%2F%2Flocalhost%3A8085%2F&prompt=select_account&response_type=code&client_id=32555940559.apps.googleusercontent.com&scope=https%3A%2F%2Fwww.googleapis.com%2Fauth%2Fuserinfo.email+https%3A%2F%2Fwww.googleapis.com%2Fauth%2Fcloud-platform+https%3A%2F%2Fwww.googleapis.com%2Fauth%2Fappengine.admin+https%3A%2F%2Fwww.googleapis.com%2Fauth%2Fcompute+https%3A%2F%2Fwww.googleapis.com%2Fauth%2Faccounts.reauth&access_type=offline


You are logged in as: [tuxninja@tuxlabs.com].

This account has no projects.

Would you like to create one? (Y/n)?  Y

After clicking allow in your browser you will be logged in…and asked about creating an initial Project. Say yes (type Y and hit enter).

Enter a Project ID. Note that a Project ID CANNOT be changed later.
Project IDs must be 6-30 characters (lowercase ASCII, digits, or
hyphens) in length and start with a lowercase letter. tuxlabsdemo
Your current project has been set to: [tuxlabsdemo].

Not setting default zone/region (this feature makes it easier to use
[gcloud compute] by setting an appropriate default value for the
--zone and --region flag).
See https://cloud.google.com/compute/docs/gcloud-compute section on how to set
default compute region and zone manually. If you would like [gcloud init] to be
able to do this for you the next time you run it, make sure the
Compute Engine API is enabled for your project on the
https://console.developers.google.com/apis page.

Your Google Cloud SDK is configured and ready to use!

Sweet your Project is now created. In order to use the Google Cloud API’s you must first enable access by visiting https://console.developers.google.com/apis/api/replicapool.googleapis.com/overview and clicking enable.

That will take a minute. Once completed you will be able to run gcloud commands against your Project. We can set the default region for our project like so:

tuxninja@tldev1:~/google-cloud-sdk$ gcloud compute project-info add-metadata --metadata google-compute-default-region=us-west1
Updated [https://www.googleapis.com/compute/v1/projects/tuxlabsdemo].
tuxninja@tldev1:~/google-cloud-sdk$ 

If you get an error here, stop being cheap and link your project to your billing account in the console.

Additionally, we want to set the default region/zone for gcloud commands like so:

tuxninja@tldev1:~$ gcloud config set compute/region us-west1
Updated property [compute/region].
tuxninja@tldev1:~$ gcloud config set compute/zone us-west1-a
Updated property [compute/zone].
tuxninja@tldev1:~$ 

Numero Dos Equis

We need to install kubectl so we can interact with Kubernetes.

tuxninja@tldev1:~$ gcloud components install kubectl


Your current Cloud SDK version is: 175.0.0
Installing components from version: 175.0.0

┌──────────────────────────────────────────────────────────────────┐
│               These components will be installed.                │
├─────────────────────┬─────────────────────┬──────────────────────┤
│         Name        │       Version       │         Size         │
├─────────────────────┼─────────────────────┼──────────────────────┤
│ kubectl             │               1.7.6 │             16.0 MiB │
│ kubectl             │                     │                      │
└─────────────────────┴─────────────────────┴──────────────────────┘

For the latest full release notes, please visit:
  https://cloud.google.com/sdk/release_notes

Do you want to continue (Y/n)?  Y

╔════════════════════════════════════════════════════════════╗
╠═ Creating update staging area                             ═╣
╠════════════════════════════════════════════════════════════╣
╠═ Installing: kubectl                                      ═╣
╠════════════════════════════════════════════════════════════╣
╠═ Installing: kubectl                                      ═╣
╠════════════════════════════════════════════════════════════╣
╠═ Creating backup and activating new installation          ═╣
╚════════════════════════════════════════════════════════════╝

Performing post processing steps...done.                                                                                                                      

Update done!

tuxninja@tldev1:~$ 

Once that is done, quickly realize someone spent an obscene amount of time making that install as pretty as it was without using ncurses. Shout out to that geek.

Numero Tres Deliquentes

Time to create our Kubernetes cluster. Run this command and “it’s going to be LEGEND….Wait for it….

tuxninja@tldev1:~$ gcloud container clusters create tuxlabs-kubernetes                           
Creating cluster tuxlabs-kubernetes...done.                                                   
Created [https://container.googleapis.com/v1/projects/tuxlabsdemo/zones/us-west1-a/clusters/tuxlabs-kubernetes].
kubeconfig entry generated for tuxlabs-kubernetes.
NAME                ZONE        MASTER_VERSION  MASTER_IP       MACHINE_TYPE   NODE_VERSION  NUM_NODES  STATUS
tuxlabs-kubernetes  us-west1-a  1.7.6-gke.1     35.197.120.249  n1-standard-1  1.7.6         3          RUNNING
tuxninja@tldev1:~$

And I hope you’re not lactose intolerant cause the second half of that word is DAIRY.” – NPH

Numero (Audi) Quattro

Now you should be able to see all running Kubernetes services in your cluster like so:

tuxninja@tldev1:~$ kubectl get --all-namespaces services
NAMESPACE     NAME                   TYPE        CLUSTER-IP      EXTERNAL-IP   PORT(S)         AGE
default       kubernetes             ClusterIP   10.19.240.1     <none>        443/TCP         15m
kube-system   default-http-backend   NodePort    10.19.254.83    <none>        80:31154/TCP    14m
kube-system   heapster               ClusterIP   10.19.247.182   <none>        80/TCP          14m
kube-system   kube-dns               ClusterIP   10.19.240.10    <none>        53/UDP,53/TCP   14m
kube-system   kubernetes-dashboard   ClusterIP   10.19.249.188   <none>        80/TCP          14m
tuxninja@tldev1:~$

And we can see the pods like so:

tuxninja@tldev1:~$ kubectl get --all-namespaces pods
NAMESPACE     NAME                                                           READY     STATUS    RESTARTS   AGE
kube-system   event-exporter-1421584133-zlvnd                                2/2       Running   0          16m
kube-system   fluentd-gcp-v2.0-1nb9x                                         2/2       Running   0          16m
kube-system   fluentd-gcp-v2.0-bpqtv                                         2/2       Running   0          16m
kube-system   fluentd-gcp-v2.0-mntjl                                         2/2       Running   0          16m
kube-system   heapster-v1.4.2-339128277-gxh5g                                3/3       Running   0          15m
kube-system   kube-dns-3468831164-5nn05                                      3/3       Running   0          15m
kube-system   kube-dns-3468831164-wcwtg                                      3/3       Running   0          16m
kube-system   kube-dns-autoscaler-244676396-fnq9g                            1/1       Running   0          16m
kube-system   kube-proxy-gke-tuxlabs-kubernetes-default-pool-6ede7d6a-nvfg   1/1       Running   0          16m
kube-system   kube-proxy-gke-tuxlabs-kubernetes-default-pool-6ede7d6a-pr82   1/1       Running   0          16m
kube-system   kube-proxy-gke-tuxlabs-kubernetes-default-pool-6ede7d6a-w6p8   1/1       Running   0          16m
kube-system   kubernetes-dashboard-1265873680-gftnz                          1/1       Running   0          16m
kube-system   l7-default-backend-3623108927-57292                            1/1       Running   0          16m
tuxninja@tldev1:~$ 

Numero Cinco (de Mayo)

You now have an active Kubernetes cluster. That is pretty sweet huh? Make sure you take the time to check out what’s running under the hood in the Google Compute Engine as well.

tuxninja@tldev1:~$ gcloud compute instances list
NAME                                               ZONE        MACHINE_TYPE   PREEMPTIBLE  INTERNAL_IP  EXTERNAL_IP     STATUS
gke-tuxlabs-kubernetes-default-pool-6ede7d6a-nvfg  us-west1-a  n1-standard-1               10.138.0.2   35.197.94.114   RUNNING
gke-tuxlabs-kubernetes-default-pool-6ede7d6a-pr82  us-west1-a  n1-standard-1               10.138.0.3   35.197.2.247    RUNNING
gke-tuxlabs-kubernetes-default-pool-6ede7d6a-w6p8  us-west1-a  n1-standard-1               10.138.0.4   35.197.117.173  RUNNING
tuxninja@tldev1:~$ 

Ok, for our final act, I promised Nginx…sigh…Let’s get this over with!

Step 1, create this nifty YAML file:

apiVersion: apps/v1beta1
kind: Deployment
metadata:
  name: nginx-deployment
spec:
  selector:
    matchLabels:
      app: nginx
  replicas: 2 # tells deployment to run 2 pods matching the template
  template: # create pods using pod definition in this template
    metadata:
      # unlike pod-nginx.yaml, the name is not included in the meta data as a unique name is
      # generated from the deployment name
      labels:
        app: nginx
    spec:
      containers:
      - name: nginx
        image: nginx:1.7.9
        ports:
        - containerPort: 80

Save it as deployment.yaml, then apply it!

tuxninja@tldev1:~$ kubectl apply -f deployment.yaml 
deployment "nginx-deployment" created
tuxninja@tldev1:~$

We can describe our deployment like this:

tuxninja@tldev1:~$ kubectl describe deployment nginx-deployment
Name:                   nginx-deployment
Namespace:              default
CreationTimestamp:      Sun, 15 Oct 2017 07:10:52 +0000
Labels:                 app=nginx
Annotations:            deployment.kubernetes.io/revision=1
                        kubectl.kubernetes.io/last-applied-configuration={"apiVersion":"apps/v1beta1","kind":"Deployment","metadata":{"annotations":{},"name":"nginx-deployment","namespace":"default"},"spec":{"replicas":2,"se...
Selector:               app=nginx
Replicas:               2 desired | 2 updated | 2 total | 2 available | 0 unavailable
StrategyType:           RollingUpdate
MinReadySeconds:        0
RollingUpdateStrategy:  25% max unavailable, 25% max surge
Pod Template:
  Labels:  app=nginx
  Containers:
   nginx:
    Image:        nginx:1.7.9
    Port:         80/TCP
    Environment:  <none>
    Mounts:       <none>
  Volumes:        <none>
Conditions:
  Type           Status  Reason
  ----           ------  ------
  Available      True    MinimumReplicasAvailable
  Progressing    True    NewReplicaSetAvailable
OldReplicaSets:  <none>
NewReplicaSet:   nginx-deployment-431080787 (2/2 replicas created)
Events:
  Type    Reason             Age   From                   Message
  ----    ------             ----  ----                   -------
  Normal  ScalingReplicaSet  3m    deployment-controller  Scaled up replica set nginx-deployment-431080787 to 2
tuxninja@tldev1:~$

And we can take a gander at the pods created for this deployment

tuxninja@tldev1:~$ kubectl get pods -l app=nginx
NAME                               READY     STATUS    RESTARTS   AGE
nginx-deployment-431080787-7131f   1/1       Running   0          4m
nginx-deployment-431080787-cgwn8   1/1       Running   0          4m
tuxninja@tldev1:~$

To see info about a specific pod run: 

tuxninja@tldev1:~$ kubectl describe pod nginx-deployment-431080787-7131f
Name:           nginx-deployment-431080787-7131f
Namespace:      default
Node:           gke-tuxlabs-kubernetes-default-pool-6ede7d6a-nvfg/10.138.0.2
Start Time:     Sun, 15 Oct 2017 07:10:52 +0000
Labels:         app=nginx
                pod-template-hash=431080787
Annotations:    kubernetes.io/created-by={"kind":"SerializedReference","apiVersion":"v1","reference":{"kind":"ReplicaSet","namespace":"default","name":"nginx-deployment-431080787","uid":"faa4d17b-b177-11e7-b439-42010...
                kubernetes.io/limit-ranger=LimitRanger plugin set: cpu request for container nginx
Status:         Running
IP:             10.16.1.4
Created By:     ReplicaSet/nginx-deployment-431080787
Controlled By:  ReplicaSet/nginx-deployment-431080787
Containers:
  nginx:
    Container ID:   docker://ce850ea012243e6d31e5eabfcc07aa71c33b3c1935e1ff1670282f22ac1d0907
    Image:          nginx:1.7.9
    Image ID:       docker-pullable://nginx@sha256:e3456c851a152494c3e4ff5fcc26f240206abac0c9d794affb40e0714846c451
    Port:           80/TCP
    State:          Running
      Started:      Sun, 15 Oct 2017 07:11:01 +0000
    Ready:          True
    Restart Count:  0
    Requests:
      cpu:        100m
    Environment:  <none>
    Mounts:
      /var/run/secrets/kubernetes.io/serviceaccount from default-token-gw047 (ro)
Conditions:
  Type           Status
  Initialized    True 
  Ready          True 
  PodScheduled   True 
Volumes:
  default-token-gw047:
    Type:        Secret (a volume populated by a Secret)
    SecretName:  default-token-gw047
    Optional:    false
QoS Class:       Burstable
Node-Selectors:  <none>
Tolerations:     node.alpha.kubernetes.io/notReady:NoExecute for 300s
                 node.alpha.kubernetes.io/unreachable:NoExecute for 300s
Events:
  Type    Reason                 Age   From                                                        Message
  ----    ------                 ----  ----                                                        -------
  Normal  Scheduled              5m    default-scheduler                                           Successfully assigned nginx-deployment-431080787-7131f to gke-tuxlabs-kubernetes-default-pool-6ede7d6a-nvfg
  Normal  SuccessfulMountVolume  5m    kubelet, gke-tuxlabs-kubernetes-default-pool-6ede7d6a-nvfg  MountVolume.SetUp succeeded for volume "default-token-gw047"
  Normal  Pulling                5m    kubelet, gke-tuxlabs-kubernetes-default-pool-6ede7d6a-nvfg  pulling image "nginx:1.7.9"
  Normal  Pulled                 5m    kubelet, gke-tuxlabs-kubernetes-default-pool-6ede7d6a-nvfg  Successfully pulled image "nginx:1.7.9"
  Normal  Created                5m    kubelet, gke-tuxlabs-kubernetes-default-pool-6ede7d6a-nvfg  Created container
  Normal  Started                5m    kubelet, gke-tuxlabs-kubernetes-default-pool-6ede7d6a-nvfg  Started container
tuxninja@tldev1:~$ 

Finally it’s time to expose Nginx to the Internet

tuxninja@tldev1:~$ kubectl expose deployment/nginx-deployment --port=80 --target-port=80 --name=nginx-deployment --type=LoadBalancer
service "nginx-deployment" exposed
tuxninja@tldev1:~

Check the status of our service

tuxninja@tldev1:~$ kubectl get svc nginx-deploymentNAME               TYPE           CLUSTER-IP     EXTERNAL-IP   PORT(S)        AGE
nginx-deployment   LoadBalancer   10.19.244.29   <pending>     80:31867/TCP   20s
tuxninja@tldev1:~$

Note the EXTERNAL-IP is in a pending state, once the LoadBalancer is created, this will have an IP address.

tuxninja@tldev1:~$ kubectl get svc nginx-deployment
NAME               TYPE           CLUSTER-IP     EXTERNAL-IP      PORT(S)        AGE
nginx-deployment   LoadBalancer   10.19.244.29   35.203.155.123   80:31867/TCP   1m
tuxninja@tldev1:~$ curl http://35.203.155.123
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>

And were all done, congratulations! 🙂

In Closing…

Kubernetes is cool as a fan, and setting it up on GCP is almost as easy as pressing the big EASY button. We have barely scraped the surface here so for continued learning I recommend buying Kubernetes Up & Running by Kelsey Hightower, Brendan Burns and Joe Beda. I would follow these folks on twitter, and in addition follow Kubernetes Co-Founder Tim Hockin as well as former Docker, Google, and now Microsoft employee/guru of all things containers Jessie Frazelle.

After you are done following these inspirational leaders in the community go to youtube and watch every Kelsey Hightower video you can find. Kelsey Hightower is perhaps the tech communities best presenter and no one has done more to educate and bring Kubernetes to the mainstream than Kelsey. So a quick shout out and thank you to Kelsey for his contributions to the community. In his honor here are two of my favorite videos from Kelsey. [ one ] [ two ].

Storing passwords securely using Pass (GPG)

Today we live in an endless sea of passwords, which are a very inefficient and ineffective means of securing our data & environments. Many companies are trying to solve this problem using a variety of techniques that all revolve around various forms of multi-factor authentication.

However, in the mean time were all screwed 😉

Just kidding. Quick PSA though, use two factor authentication at a minimum everywhere you can ESPECIALLY your email, since it’s used for password recovery on other sites. Ok then moving on…

There are many password managers like LastPass and 1Password, which do a fairly effective job at providing convenience and prevent you from scribbling down your passwords on paper (STOP IT !!!). However, I personally can’t get passed the whole ‘store all my passwords in one super secure vault on the Internet’ thing. To be fair some of these password managers can be downloaded on your machine and ran locally, but there are two other drawbacks to those I found.

  1. Some of them are not free and…
  2. Some of them have ugly and clunky UI’s

So what do I like/use then ? I use something called ‘pass’. Which is a command line utility that wraps GPG. The reason I use it is because…

  1. I love using command line utilities over GUI, I find it far more convenient and…
  2. I was going to write this exact utility (a GPG wrapper) until I found out someone else did and…
  3. Because I like GPG.

At most of the organizations I have worked at, password management was done poorly i.e. everyone used different approaches and there was no governance or oversight. I hope with this article to make folks aware of what I feel is a simple, effective method that every unix savvy administrator should use.

FYI Pass provides migration scripts from the most popular password manager tools on their website.

Introducing Pass

From the Pass site “Password management should be simple and follow Unix philosophy. With pass, each password lives inside of a gpg encrypted file whose filename is the title of the website or resource that requires the password. These encrypted files may be organized into meaningful folder hierarchies, copied from computer to computer, and, in general, manipulated using standard command line file management utilities.”

Where Can You Get or Learn More About Pass ? 

https://www.passwordstore.org/

Installing Pass

Depending on your operating system there are various ways to install

Ubuntu/Debian

sudo apt-get install pass

Fedora / RHEL

sudo yum install pass

Mac

brew install pass
echo "source /usr/local/etc/bash_completion.d/password-store" >> ~/.bashrc

Since I already installed pass on my Mac a while back I will be installing it on a Docker container with Ubuntu 16.04.

root@0b415380eb80:/# apt-get install -y pass

After pass successfully installs, try running it

root@0b415380eb80:/# pass
Error: password store is empty. Try "pass init".
root@0b415380eb80:/#

Well that is pretty straight forward, it appears we need to initiliaze the db.

root@0b415380eb80:/# pass init
Usage: pass init [--path=subfolder,-p subfolder] gpg-id...
root@0b415380eb80:/#

Looks like we need to provide ‘key’…can that be just anything?

root@0b415380eb80:/# pass init "tuxlabs Password Key"
mkdir: created directory '/root/.password-store/'
Password store initialized for tuxlabs Password Key
root@0b415380eb80:/# pass
Password Store
root@0b415380eb80:/#

Now our password store looks initialized ! Let’s try inserting a password into the DB !

root@0b415380eb80:/# pass insert Gmail/myemail
mkdir: created directory '/root/.password-store/Gmail'
Enter password for Gmail/myemail:
Retype password for Gmail/myemail:
gpg: tuxlabs Password Key: skipped: No public key
gpg: [stdin]: encryption failed: No public key
root@0b415380eb80:/#

Uh oh what happened ? Well remember I said it uses GPG, and we not only don’t have a gpg key setup in our Docker container, but we initialized our Pass DB without using a GPG Key (the whole point) !

root@0b415380eb80:/# gpg --list-keys
root@0b415380eb80:/#

To remedy this we need to create a GPG key

Creating your GPG Key

root@0b415380eb80:/# gpg --gen-key
gpg (GnuPG) 1.4.20; Copyright (C) 2015 Free Software Foundation, Inc.
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.

Please select what kind of key you want:
   (1) RSA and RSA (default)
   (2) DSA and Elgamal
   (3) DSA (sign only)
   (4) RSA (sign only)
Your selection? 1
RSA keys may be between 1024 and 4096 bits long.
What keysize do you want? (2048) 4096
Requested keysize is 4096 bits
Please specify how long the key should be valid.
         0 = key does not expire
      <n>  = key expires in n days
      <n>w = key expires in n weeks
      <n>m = key expires in n months
      <n>y = key expires in n years
Key is valid for? (0)
Key does not expire at all
Is this correct? (y/N) y

You need a user ID to identify your key; the software constructs the user ID
from the Real Name, Comment and Email Address in this form:
    "Heinrich Heine (Der Dichter) <heinrichh@duesseldorf.de>"

Real name: Tuxninja
Email address: tuxninja@tuxlabs.com
Comment: TuxLabs
You selected this USER-ID:
    "Tuxninja (TuxLabs) <tuxninja@tuxlabs.com>"

Change (N)ame, (C)omment, (E)mail or (O)kay/(Q)uit? O
You need a Passphrase to protect your secret key.

gpg: gpg-agent is not available in this session
We need to generate a lot of random bytes. It is a good idea to perform
some other action (type on the keyboard, move the mouse, utilize the
disks) during the prime generation; this gives the random number
generator a better chance to gain enough entropy.
............+++++
...................+++++
We need to generate a lot of random bytes. It is a good idea to perform
some other action (type on the keyboard, move the mouse, utilize the
disks) during the prime generation; this gives the random number
generator a better chance to gain enough entropy.
...+++++
+++++
gpg: key 5B2F89A5 marked as ultimately trusted
public and secret key created and signed.

gpg: checking the trustdb
gpg: 3 marginal(s) needed, 1 complete(s) needed, PGP trust model
gpg: depth: 0  valid:   1  signed:   0  trust: 0-, 0q, 0n, 0m, 0f, 1u
pub   4096R/5B2F89A5 2016-12-14
      Key fingerprint = 5FF6 1717 4415 03FF D455  7516 CF8E 1BDC 5B2F 89A5
uid                  Tuxninja (TuxLabs) <tuxninja@tuxlabs.com>
sub   4096R/EF0F232F 2016-12-14

root@0b415380eb80:/#

To view your GPG key run

root@0b415380eb80:/# gpg --list-keys
/root/.gnupg/pubring.gpg
------------------------
pub   4096R/5B2F89A5 2016-12-14
uid                  Tuxninja (TuxLabs) <tuxninja@tuxlabs.com>
sub   4096R/EF0F232F 2016-12-14

root@0b415380eb80:/#

Now we can see we have one GPG key, with the ID 5B2F89A5

Let’s try re-initializing Pass. 

root@0b415380eb80:/# pass init "5B2F89A5"
Password store initialized for 5B2F89A5
root@0b415380eb80:/#

But we have a problem, re-initializing Pass doesn’t get rid of our previous insert into the db. As you can see here our Pass DB is effectively corrupt.

root@0b415380eb80:~# pass
Password Store
`-- Gmail
root@0b415380eb80:~# pass rm Gmail
Are you sure you would like to delete Gmail? [y/N] y
rm: cannot remove '/root/.password-store/Gmail': Is a directory
root@0b415380eb80:~# pass rm Gmail/myemail
Error: Gmail/myemail is not in the password store.
root@0b415380eb80:~#

Hmmm, what’s a guy to do….

root@0b415380eb80:~# rm -rf .password-store/Gmail/
root@0b415380eb80:~# pass
Password Store
root@0b415380eb80:~#

Yes it really was that simple, and that is one more reason why I love pass.

You can also initialize your password store using git for version control, see the passwordstore.org website for more info !

Now let’s insert some good stuff.

Inserting A Password into Pass

root@0b415380eb80:~# pass insert Gmail/myemail
Enter password for Gmail/myemail:
Retype password for Gmail/myemail:
root@0b415380eb80:~# pass
Password Store
`-- Gmail
    `-- myemail
root@0b415380eb80:~#

That seems to have worked. Let’s try to retrieve the pass.

Retrieving A Password In Pass

root@0b415380eb80:~# pass Gmail/myemail
gpg: starting migration from earlier GnuPG versions
gpg: porting secret keys from '/root/.gnupg/secring.gpg' to gpg-agent
gpg: migration succeeded
testpass
root@0b415380eb80:~# pass Gmail/myemail
testpass
root@0b415380eb80:~#

Note, I retrieve the password twice using my GPG Passsword (You will be prompted through a curses interface to enter your passphrase). Then I run it again, because of the initial GPG migration messages just to show how it would normally work after you’ve used GPG once with Pass.

Now let’s say someone is standing over your shoulder, you want to access your passsword, but you don’t want them to see it. You can get it straight to your clipboard by using -c.

Copying Passwords To Your Clipboard

pass -c Gmail/myemail
Copied Gmail/myemail to clipboard. Will clear in 45 seconds.

Docker Issue ?

Notice the prompt is not included in the above example ? That is cause it didn’t actually work. Apparently, it doesn’t work in Docker due to not having display dependencies installed/configured. So what I show above is the output from my mac…but my actual Docker related error was.

root@0b415380eb80:~# pass -c Gmail/myemail
Error: Can't open display: (null)
Error: Could not copy data to the clipboard
root@0b415380eb80:~#

There might be an easy way to fix this (like install X), but I don’t usually use Docker for storing my passwords I just happen to be using it for this tutorial, so moving on !

Folders

It’s also important to note that Pass supports folder structures, as shown in my example I am creating a ‘Gmail’ folder and placing a password file called ‘myemail’ with my password in it. In reality I recommend not naming the file after your account/email and using the multiline version to encrypt those details as well. That way you can just stick to the site name for the name of the encrypted file in whatever folder or in the top level of Pass.

Multiline Encrypted Files with Pass

A common use case with Pass is adding an entire encrypted file so you can store more than just a password…

root@0b415380eb80:~# pass insert -m tuxlabs/databases
mkdir: created directory '/root/.password-store/tuxlabs'
Enter contents of tuxlabs/databases and press Ctrl+D when finished:

this is an example of a multiline
encrypted file
this way you can store more than just a password you can store user/pass/url etc
root@0b415380eb80:~# pass
Password Store
|-- Gmail
|   `-- myemail
`-- tuxlabs
    `-- databases
root@0b415380eb80:~#

Again retrieving it is as easy as..

root@0b415380eb80:~# pass tuxlabs/databases
this is an example of a multiline
encrypted file
this way you can store more than just a password you can store user/pass/url etc
root@0b415380eb80:~#

Finally if you no longer want the info to be stored in Pass…

If you want to copy you password to the clipboard from a multiline file, you must store your password on the first line of the file !

Deleting An Entry In Pass

root@0b415380eb80:~# pass rm Gmail/myemail
Are you sure you would like to delete Gmail/myemail? [y/N] y
removed '/root/.password-store/Gmail/myemail.gpg'
root@0b415380eb80:~# pass rm tuxlabs/databases
Are you sure you would like to delete tuxlabs/databases? [y/N] y
removed '/root/.password-store/tuxlabs/databases.gpg'
root@0b415380eb80:~# pass
Password Store
root@0b415380eb80:~#

Another thing, the output on my mac is much prettier than this `– thing I am getting in the Ubuntu Docker container… Not sure if that’s an Ubuntu issue or Docker, but on the Mac the output is much prettier, which can be seen on the passwordstore.org home page.

So that’s it, Pass is pretty straight forward, easy to work with, depends on GPG security and that is why I like it.

Stay secure, until next time !