commit b720b732185259a0e9d91a878ed23610d9fc66d4 Author: ducoterra Date: Fri May 22 21:27:19 2020 -0400 project userspace part 1 diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..f913501 --- /dev/null +++ b/.gitignore @@ -0,0 +1,5 @@ +*.crt +*.key +*.srl +*.csr +users/ \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..e3d7f02 --- /dev/null +++ b/README.md @@ -0,0 +1,150 @@ +# Project Userspace + +## One provisioner to rule them all + +### Quickstart + +```bash +kubectl -n kube-system create secret generic certsigner --from-file /var/lib/rancher/k3s/server/tls/client-ca.crt --from-file /var/lib/rancher/k3s/server/tls/client-ca.key +kubectl apply -f cluster +kubectl apply -f certsigner +./adduser.sh tester +./userspace.sh tester +``` + +### Objectives + +1. Provision a namespace with clusterroles, rolebindings, and a dedicated nfs-provisioner with one helm chart +2. Create an easy way for users to sign their certificates +3. Create a cleanup script without deleting user data +4. profit + +### Userspace + +1. Namespace + +```yaml +apiVersion: v1 +kind: Namespace +metadata: + name: {{ .Release.Name }} +``` + +1. Rolebinding + +```yaml +kind: RoleBinding +apiVersion: rbac.authorization.k8s.io/v1beta1 +metadata: + namespace: {{ .Release.Name }} + name: namespace-manager +subjects: +- kind: User + name: {{ .Release.Name }} + apiGroup: "" +roleRef: + kind: ClusterRole + name: namespace-manager + apiGroup: "" +``` + +### Create a kubernetes certsigner pod + +This keeps the client-ca crt and key secret and allows the cert to be signed and stored on the pod + +#### Create the certsigner secret + +```bash +kubectl -n kube-system create secret generic certsigner --from-file /var/lib/rancher/k3s/server/tls/client-ca.crt --from-file /var/lib/rancher/k3s/server/tls/client-ca.key +``` + +#### Set up the certsigner pod + +```bash +kubectl --context admin apply -f certsigner +``` + +#### Generate a cert + +```bash +export USER= +docker run -it -v $(pwd)/users/$USER:/$USER python:latest openssl genrsa -out /$USER/$USER.key 2048 +docker run -it -v $(pwd)/users/$USER:/$USER python:latest openssl req -new -key /$USER/$USER.key -out /$USER/$USER.csr -subj "/CN=$USER/O=user" +``` + +#### Create a new Userspace + +```bash +helm template $USER ./namespace | kubectl --context admin apply -f - +``` + +#### Sign the cert + +```bash +export USER= +kubectl --context admin cp $(pwd)/users/$USER/$USER.csr certsigner:/certs/$USER.csr +kubectl --context admin exec -it --context admin certsigner -- openssl x509 -in /certs/$USER.csr -req -CA /keys/client-ca.crt -CAkey /keys/client-ca.key -CAcreateserial -out /certs/$USER.crt -days 5000 +kubectl --context admin cp certsigner:/certs/$USER.crt $(pwd)/users/$USER/$USER.crt +``` + +#### Add to the config + +```bash +kubectl config set-credentials $USER --client-certificate=$USER.crt --client-key=$USER.key +kubectl config set-context $USER --cluster=mainframe --namespace=$USER --user=$USER +``` + +#### Delete + +```bash +kubectl config delete-context $USER +helm template $USER ./namespace | kubectl --context admin delete -f - +``` + +### Signing a user cert - detailed notes + +NOTE: ca.crt and ca.key are in /var/lib/rancher/k3s/server/tls/client-ca.* + +```bash +# First we create the credentials +# /CN= - the user +# /O= - the group + +# Navigate to the user directory +export USER= +cd $USER + +# Generate a private key +openssl genrsa -out $USER.key 2048 +# Check the key +# openssl pkey -in ca.key -noout -text +# Generate and send me the CSR +# The "user" group is my default group +openssl req -new -key $USER.key -out $USER.csr -subj "/CN=$USER/O=user" + +# Check the CSR +# openssl req -in $USER.csr -noout -text +# If satisfactory, sign the CSR +# Copy from /var/lib/rancher/k3s/server/tls/client-ca.crt and client-ca.key +openssl x509 -req -in $USER.csr -CA ../client-ca.crt -CAkey ../client-ca.key -CAcreateserial -out $USER.crt -days 5000 +# Review the certificate +# openssl x509 -in $USER.crt -text -noout + +# Send back the crt +# cp $USER.crt $USER.key ../server-ca.crt ~/.kube/ +kubectl config set-credentials $USER --client-certificate=$USER.crt --client-key=$USER.key +kubectl config set-context $USER --cluster=mainframe --namespace=$USER --user=$USER + +# Now we create the namespace, rolebindings, and resource quotas +# kubectl apply -f k8s/ + +# Add the cluster +# CA file can be found at https://3.14.3.100:6443/cacerts +- cluster: + certificate-authority: server-ca.crt + server: https://3.14.3.100:6443 + name: mainframe + +# Test if everything worked +kubectl --context=$USER-context get pods +``` \ No newline at end of file diff --git a/certsigner/pod.yaml b/certsigner/pod.yaml new file mode 100644 index 0000000..27f97ff --- /dev/null +++ b/certsigner/pod.yaml @@ -0,0 +1,31 @@ +apiVersion: v1 +kind: Pod +metadata: + name: certsigner + namespace: kube-system +spec: + containers: + - name: certsigner + image: python:latest + command: ["cat"] + tty: true + resources: + requests: + memory: 1Mi + cpu: 1m + limits: + memory: 100Mi + cpu: 100m + volumeMounts: + - mountPath: /certs + name: certs + - mountPath: /keys + name: keys + volumes: + - name: certs + persistentVolumeClaim: + claimName: certsigner-certs + - name: keys + secret: + secretName: certsigner + restartPolicy: Always \ No newline at end of file diff --git a/certsigner/pvc.yaml b/certsigner/pvc.yaml new file mode 100644 index 0000000..dae645c --- /dev/null +++ b/certsigner/pvc.yaml @@ -0,0 +1,11 @@ +apiVersion: v1 +kind: PersistentVolumeClaim +metadata: + name: certsigner-certs + namespace: kube-system +spec: + accessModes: + - ReadWriteOnce + resources: + requests: + storage: 1Gi \ No newline at end of file diff --git a/cluster/clusterrole.yaml b/cluster/clusterrole.yaml new file mode 100644 index 0000000..4eeb642 --- /dev/null +++ b/cluster/clusterrole.yaml @@ -0,0 +1,15 @@ +kind: ClusterRole +apiVersion: rbac.authorization.k8s.io/v1beta1 +metadata: + name: cluster-readonly +rules: +- apiGroups: + - "" + - rbac.authorization.k8s.io + - storage.k8s.io + - networking.k8s.io + - traefik.containo.us + resources: + - storageclasses + verbs: + - list \ No newline at end of file diff --git a/cluster/clusterrolebinding.yaml b/cluster/clusterrolebinding.yaml new file mode 100644 index 0000000..a6df770 --- /dev/null +++ b/cluster/clusterrolebinding.yaml @@ -0,0 +1,12 @@ +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + name: cluster-readonly +subjects: +- kind: Group + name: user + apiGroup: "" +roleRef: + kind: ClusterRole + name: cluster-readonly + apiGroup: "" \ No newline at end of file diff --git a/createuser.sh b/createuser.sh new file mode 100755 index 0000000..7f573d4 --- /dev/null +++ b/createuser.sh @@ -0,0 +1,5 @@ +#!/bin/bash + +export USER=$1 +docker run -it -v $(pwd)/users/$USER:/$USER python:latest openssl genrsa -out /$USER/$USER.key 2048 +docker run -it -v $(pwd)/users/$USER:/$USER python:latest openssl req -new -key /$USER/$USER.key -out /$USER/$USER.csr -subj "/CN=$USER/O=user" \ No newline at end of file diff --git a/namespace/.helmignore b/namespace/.helmignore new file mode 100644 index 0000000..0e8a0eb --- /dev/null +++ b/namespace/.helmignore @@ -0,0 +1,23 @@ +# Patterns to ignore when building packages. +# This supports shell glob matching, relative path matching, and +# negation (prefixed with !). Only one pattern per line. +.DS_Store +# Common VCS dirs +.git/ +.gitignore +.bzr/ +.bzrignore +.hg/ +.hgignore +.svn/ +# Common backup files +*.swp +*.bak +*.tmp +*.orig +*~ +# Various IDEs +.project +.idea/ +*.tmproj +.vscode/ diff --git a/namespace/Chart.yaml b/namespace/Chart.yaml new file mode 100644 index 0000000..cf7bc40 --- /dev/null +++ b/namespace/Chart.yaml @@ -0,0 +1,23 @@ +apiVersion: v2 +name: helm +description: A Helm chart for Kubernetes + +# A chart can be either an 'application' or a 'library' chart. +# +# Application charts are a collection of templates that can be packaged into versioned archives +# to be deployed. +# +# Library charts provide useful utilities or functions for the chart developer. They're included as +# a dependency of application charts to inject those utilities and functions into the rendering +# pipeline. Library charts do not define any templates and therefore cannot be deployed. +type: application + +# 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/) +version: 0.1.0 + +# This is the version number of the application being deployed. This version number should be +# incremented each time you make changes to the application. Versions are not expected to +# follow Semantic Versioning. They should reflect the version the application is using. +appVersion: 1.16.0 diff --git a/namespace/templates/namespace.yaml b/namespace/templates/namespace.yaml new file mode 100644 index 0000000..770073e --- /dev/null +++ b/namespace/templates/namespace.yaml @@ -0,0 +1,4 @@ +apiVersion: v1 +kind: Namespace +metadata: + name: {{ .Release.Name }} \ No newline at end of file diff --git a/namespace/templates/role.yaml b/namespace/templates/role.yaml new file mode 100644 index 0000000..ce04e74 --- /dev/null +++ b/namespace/templates/role.yaml @@ -0,0 +1,96 @@ +kind: Role +apiVersion: rbac.authorization.k8s.io/v1beta1 +metadata: + name: namespace-manager + namespace: {{ .Release.Name }} +rules: +- apiGroups: + - "" + - extensions + - apps + - batch + - autoscaling + - networking.k8s.io + - traefik.containo.us + - rbac.authorization.k8s.io + - metrics.k8s.io + resources: + - deployments + - replicasets + - pods + - pods/exec + - pods/log + - pods/attach + - daemonsets + - statefulsets + - replicationcontrollers + - horizontalpodautoscalers + - services + - ingresses + - persistentvolumeclaims + - jobs + - cronjobs + - secrets + - configmaps + - serviceaccounts + - rolebindings + - ingressroutes + - middlewares + - endpoints + verbs: + - "*" +- apiGroups: + - "" + - metrics.k8s.io + - rbac.authorization.k8s.io + resources: + - resourcequotas + - roles + verbs: + - list +--- +kind: Role +apiVersion: rbac.authorization.k8s.io/v1beta1 +metadata: + name: namespace-readonly + namespace: {{ .Release.Name }} +rules: +- apiGroups: + - "" + - extensions + - apps + - batch + - autoscaling + - networking.k8s.io + - traefik.containo.us + - rbac.authorization.k8s.io + - metrics.k8s.io + - storage.k8s.io + resources: + - deployments + - replicasets + - pods + - pods/exec + - pods/log + - pods/attach + - daemonsets + - statefulsets + - replicationcontrollers + - horizontalpodautoscalers + - services + - ingresses + - persistentvolumeclaims + - jobs + - cronjobs + - secrets + - configmaps + - serviceaccounts + - rolebindings + - ingressroutes + - middlewares + - resourcequotas + - roles + - endpoints + verbs: + - list + - watch \ No newline at end of file diff --git a/namespace/templates/rolebinding.yaml b/namespace/templates/rolebinding.yaml new file mode 100644 index 0000000..4a89339 --- /dev/null +++ b/namespace/templates/rolebinding.yaml @@ -0,0 +1,13 @@ +kind: RoleBinding +apiVersion: rbac.authorization.k8s.io/v1beta1 +metadata: + name: namespace-manager + namespace: {{ .Release.Name }} +subjects: +- kind: User + name: {{ .Release.Name }} + apiGroup: "" +roleRef: + kind: Role + name: namespace-manager + apiGroup: "" \ No newline at end of file diff --git a/namespace/values.yaml b/namespace/values.yaml new file mode 100644 index 0000000..e69de29 diff --git a/userspace.sh b/userspace.sh new file mode 100644 index 0000000..332574b --- /dev/null +++ b/userspace.sh @@ -0,0 +1,9 @@ +#!/bin/bash + +export USER=$1 +helm template $USER ./namespace | kubectl --context admin apply -f - +kubectl --context admin cp $(pwd)/users/$USER/$USER.csr certsigner:/certs/$USER.csr +kubectl --context admin exec --context admin certsigner -- openssl x509 -in /certs/$USER.csr -req -CA /keys/client-ca.crt -CAkey /keys/client-ca.key -set_serial $(python -c "import random; print(random.randint(1000000000, 9999999999))") -out /certs/$USER.crt -days 5000 +kubectl --context admin cp certsigner:/certs/$USER.crt $(pwd)/users/$USER/$USER.crt +kubectl config set-credentials $USER --client-certificate=$(pwd)/users/$USER/$USER.crt --client-key=$(pwd)/users/$USER/$USER.key +kubectl config set-context $USER --cluster=mainframe --namespace=$USER --user=$USER