Skip to content

A Kubernetes Operator to manage secrets stored in LastPass password manager

License

Notifications You must be signed in to change notification settings

edgelevel/lastpass-operator

Repository files navigation

lastpass-operator

Build Status Docker Tag Docker Pulls

A Kubernetes Operator to manage secrets stored in LastPass password manager

How it works

Suppose you have some credentials stored in LastPass

$ lpass show example/my-secret --json
[
  {
    "id": "8190226423897406876",
    "name": "my-secret",
    "fullname": "example/my-secret",
    "username": "whoami",
    "password": "s3cr3t",
    "last_modified_gmt": "1562690587",
    "last_touch": "0",
    "group": "example",
    "url": "https://lastpass.com",
    "note": "{\"myKey\":\"myValue\"}"
  }
]

Define a LastPass or LastPassGroup Custom Resource to automatically manage the lifecycle of your secrets in Kubernetes

$ cat example/edgelevel_v1alpha1_lastpass_cr.yaml
apiVersion: edgelevel.com/v1alpha1
kind: LastPass
metadata:
  name: example-lastpass
spec:
  secretRef:
    group: example
    name: my-secret
    withUsername: true
    withPassword: true
    withUrl: true
    withNote: true
  syncPolicy:
    enabled: true
    refresh: 10

# create a custom resource
$ kubectl apply -f example/edgelevel_v1alpha1_lastpass_cr.yaml

NOTE: The LastPassGroup custom resource will sync all the secrets in a lastpass folder to kubernetes. The lastpass group will not sync subfolders.

$ cat example/edgelevel_v1alpha1_lastpassgroup_cr.yaml
apiVersion: edgelevel.com/v1alpha1
kind: LastPassGroup
metadata:
  name: example-lastpassgruop
spec:
  secretRef:
    group: example
    withUsername: true
    withPassword: true
    withUrl: true
    withNote: true
  syncPolicy:
    enabled: true
    refresh: 10

# create a custom resource
$ kubectl apply -f example/edgelevel_v1alpha1_lastpassgroup_cr.yaml

The operator will take care of create native Kubernetes secrets and keep them up to date that if they change

# verify
$ kubectl get lastpass
$ kubectl get secrets

# inspect
$ kubectl get secret example-lastpass-8190226423897406876 -o yaml
apiVersion: v1
data:
  NOTE: eyJteUtleSI6Im15VmFsdWUifQ==
  PASSWORD: czNjcjN0
  URL: aHR0cHM6Ly9sYXN0cGFzcy5jb20=
  USERNAME: d2hvYW1p
kind: Secret
metadata:
  annotations:
    fullname: example/my-secret
    group: example
    id: "8190226423897406876"
    lastModifiedGmt: "1562690587"
    lastTouch: "0"
    name: my-secret
  creationTimestamp: "2019-07-09T15:00:13Z"
  labels:
    app: lastpass-operator
  name: example-lastpass-8190226423897406876
  namespace: default
  ownerReferences:
  - apiVersion: edgelevel.com/v1alpha1
    blockOwnerDeletion: true
    controller: true
    kind: LastPass
    name: example-lastpass
    uid: 0687d5a7-5f02-4ee4-a6c4-011c734f4149
  resourceVersion: "113312"
  selfLink: /api/v1/namespaces/default/secrets/example-lastpass-8190226423897406876
  uid: 382008d2-8999-444d-86c8-e4f29eecbe9f
type: Opaque

# check values
$ echo 'czNjcjN0' | base64 --decode
s3cr3t
$ echo 'eyJteUtleSI6Im15VmFsdWUifQ==' | base64 --decode | jq -c
{"myKey":"myValue"}

Metrics are exposed by default in Prometheus format, see an example

# port forward
kubectl port-forward service/lastpass-operator -n lastpass 8080:8383

# request metrics
http :8080/metrics

Considerations

  • If you want to understand how the operator works, you should have a look at the Reconcile method defined in lastpass_controller and at the CustomResourceDefinition
  • The diagram below explains the core logic of the reconcile loop

reconcile-loop

  • The recommended way to install the operator in a cluster is by applying the provided Helm chart
  • TODO for a working example you should have a look at niqdev/do-k8s
  • This operator has been mainly developed to simplify the secret management of low security environments, if you are a security paranoid you should audit this project and assess if it meets the security standard of your organization
  • The operator, for obvious reasons, won't work if you have MFA enabled on LastPass or your credentials "Require Password Reprompt"
  • Once this Argo CD feature will be implemented it should allow to bind secrets directly to an Application

Development

# download source
mkdir -p $GOPATH/src/github.com/edgelevel && cd $_
git clone git@github.com:edgelevel/lastpass-operator.git
cd lastpass-operator

# install operator-sdk
.travis/install_operator_sdk.sh

# install dependencies
go mod download -x

Run locally outside the cluster on minkube

# requires virtualbox
minikube start

# run locally
export OPERATOR_NAME=lastpass-operator
export LASTPASS_USERNAME=myUsername
export LASTPASS_PASSWORD=myPassword

# Install CRDs into cluster
make install

# Start lastpass operator
make run

# Alternatively you can install and run with
make install run

Run as a Deployment inside the cluster

# apply chart
helm template \
  --values chart/values.yaml \
  --set lastpass.username="myUsername" \
  --set lastpass.password="myPassword" \
  chart/ | kubectl apply -n lastpass -f -

Debug issues

# verify logs
kubectl logs deployment/lastpass-operator -n lastpass -f

Publish a new version on DockerHub

# build and publish manually (unsafe)
make docker-build IMG=edgelevel/lastpass-operator:X.Y.Z
make docker-push IMG=edgelevel/lastpass-operator:X.Y.Z

# build and publish using travis
git tag vX.Y.Z
git push origin --tags

TODO