init: basic k8s deployment on DO

This commit is contained in:
2024-01-09 17:39:03 +01:00
commit b826035b3a
15 changed files with 362 additions and 0 deletions
+2
View File
@@ -0,0 +1,2 @@
*.pdf
local/
@@ -0,0 +1,16 @@
apiVersion: external-secrets.io/v1beta1
kind: SecretStore
metadata:
name: kemkas-secret-store
namespace: kemkas
spec:
provider:
onepassword:
connectHost: https://1password-connect.dev.kemkas.hu
vaults:
kemkas: 1 # look in this vault first
auth:
secretRef:
connectTokenSecretRef:
name: onepassword-connect-token
key: token
@@ -0,0 +1,8 @@
apiVersion: v1
kind: Secret
metadata:
name: onepassword-connect-token
namespace: kemkas
type: Opaque
stringData:
token: <insert-token-from-1password>
@@ -0,0 +1,14 @@
server {
listen 80;
server_name 1password-connect.dev.kemkas.hu;
location / {
proxy_pass_request_headers on;
proxy_pass http://localhost:8080;
}
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root /usr/share/nginx/html;
}
}
@@ -0,0 +1,20 @@
version: "3.4"
services:
op-connect-api:
image: 1password/connect-api:latest
ports:
- "8080:8080"
volumes:
- "./1password-credentials.json:/home/opuser/.op/1password-credentials.json"
- "data:/home/opuser/.op/data"
op-connect-sync:
image: 1password/connect-sync:latest
ports:
- "8081:8080"
volumes:
- "./1password-credentials.json:/home/opuser/.op/1password-credentials.json"
- "data:/home/opuser/.op/data"
volumes:
data:
+79
View File
@@ -0,0 +1,79 @@
# Kemkas k8s Deployment
## ToC
- [Argo CD](#argo-cd)
- [1password ESO connect server](#1password-connect-server)
- [Kemkas](#kemkas)
## Argo CD
Goal: continous deployment automation with rollback capability
Files:
- [argocd-ingress.yml](./argocd/argocd-ingress.yaml) for connecting the service with the load balancer and nginx reverse proxy
- [argocd-values.yml](./argocd/argocd-values.yaml) config for the argocd helm chart to use SSL termination at NGINX.
- [cert-manager-issuer.yaml](./argocd/cert-manager-issuer.yaml) SSL certificate config for the argocd.kemkas.hu domain
TODO:
- [ ] gRPC setup for ArgoCD to use the CLI. Workaround: k8s port proxy to localhost.
Setup instructions
1. DO 1-click install argoCD into k8s cluster (TODO: replace with helm install command, I suspect behind the scenes the 1-click install does the same)
1. DO 1-click install ingress-nginx into k8s cluster (TODO: replace with helm install command, I suspect behind the scenes the 1-click install does the same)
1. DO 1-click install cert-manager into k8s cluster (TODO: replace with helm install command, I suspect behind the scenes the 1-click install does the same)
1. Create DNS A record for argocd.kemkas.hu pointing to the Load Balancer IP address (Load balancer is a DO object created with the ingress-nginx helm chart install)
1. helm update argocd with `argocd-values.yaml`
1. Apply all files in `argocd` directory
```
kubectl apply -f cert-manager-issuer.yaml
kubectl apply -f argocd-ingress.yaml
```
## 1Password Connect Server
Goal: Store secrets in 1password instead of kubernetes, so we can push all kubernetes config while keeping the secrets safe in 1password
Files:
- [1password-secret-store.yaml](./1password-connect-server/1password-secret-store.yaml): kuberentes ESO Secret Store to be referenced by external secrets
- [connect-server-access-token-secret.yaml](./1password-connect-server/connect-server-access-token-secret.yaml): kubernetes secret file to connect with the 1password connect server without the actual secret token. the token can be generated on 1password website or CLI.
- [docker-compose.yaml](./1password-connect-server/docker-compose.yaml): docker compose config to run the 1password connect server on a separate machine. Requires a `1password-credentials.json` file locally in the same directory, which can be obtained from the 1password website or CLI.
- [connect-server.conf](./1password-connect-server/connect-server.conf) nginx config for the SSL terminating proxy for the 1password connect server (so that secrets don't travel unencrypted)
TODO:
- [ ] explore running the 1password connect server on the same k8s cluster to simplify infrastructure
- [ ] write script to automate the setup instraction (using `doctl` for full infra automation)
Setup:
1. create DO droplet (with docker template)
1. create DNS A record pointing to the droplet
1. install nginx, certbot `sudo apt install nginx certbot python3-certbot-nginx`
1. copy `docker-compose.yaml` and `1password-credentials.json` to the droplet and run `docker compose up -d`
1. copy connect-server nginx config to `/etc/nginx/sites-available` and link it to sites enabled `ln -s /etc/nginx/sites-available/connect-server.conf /etc/nginx/sites-enabled/`
1. test nginx config `nginx -t`
1. reload nginx config `nginx -s reload`
1. create SSL certificate with certbot `certbot --nginx -d 1password-connect.dev.kemkas.hu` (email address and accepting terms is required!)
1. setup firewall to block TCP/8080 and TCP/8081 to avoid unencrypted access to the connect server (allow TCP/443 and TCP/22)
1. helm install the external secret operator `helm repo add external-secrets https://charts.external-secrets.io` and `helm install external-secrets external-secrets/external-secrets -n external-secrets --create-namespace --set installCRDs=false` (from [https://external-secrets.io/](https://external-secrets.io/))
1. create namespace for secret store `kubectl create ns kemkas`
1. create connect server access token secret in k8s `kubectl apply -f ./1password-connect-server/connect-server-access-token-secret.yaml`
1. create secret store `kubectl apply -f ./1password-connect-server/1password-secret-store.yaml`
## Kemkas
Goal: deploy an existing docker image into the k8s cluster with proper secrets and expose it on HTTPS with proper SSL cert
Files:
- [kemkas-external-secrets.yaml](./kemkas/kemkas-external-secrets.yaml): syncs external secrets from the 1password secret store
- [kemkas-deployment.yaml](./kemkas/kemkas-deployment.yaml): configures the kemkas server docker image to run on the cluster
- [kemkas-service.yaml](./kemkas/kemkas-service.yaml): exposes the kemkas server deployment to the cluster
- [kemkas-ssl-cert-issuer.yaml](./kemkas/kemkas-ssl-cert-issuer.yaml): config for issuing SSL certs for accessing the kemkas server on the internet
- [kemkas-ingress.yaml](./kemkas/kemkas-ingress.yaml): exposes the kemkas server on the internet through the nginx ingress proxy
Setup:
1. connect Digital Ocean Container Registry to the k8s cluster `doctl registry kubernetes-manifest | kubectl apply -f -`
1. create external secrets for the upcoming kemkas deployment `kubectl apply -f ./kemkas/kemkas-external-secrets.yaml`
1. create kemkas deployment `kubectl apply -f ./kemkas/kemkas-deployment.yaml`
1. create service to export the kemkas deployment `kubectl apply -f ./kemkas/kemkas-service.yaml`
1. create SSL cert issuer `kubectl apply -f ./kemkas/kemkas-ssl-cert-issuer.yaml`
1. create ingress for the kemkas service `kubectl apply -f ./kemkas/kemkas-ingress.yaml`
+26
View File
@@ -0,0 +1,26 @@
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: ingress-argocd
namespace: argocd
annotations:
nginx.ingress.kubernetes.io/force-ssl-redirect: "true"
nginx.ingress.kubernetes.io/backend-protocol: "HTTP"
cert-manager.io/issuer: letsencrypt-argocd
spec:
ingressClassName: nginx
rules:
- http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: argocd-server
port:
name: http
host: argocd.kemkas.hu
tls:
- hosts:
- argocd.kemkas.hu
secretName: letsencrypt-argocd
+5
View File
@@ -0,0 +1,5 @@
server:
ingress:
enabled: "true"
extraArgs:
- "--insecure"
+20
View File
@@ -0,0 +1,20 @@
apiVersion: cert-manager.io/v1
kind: Issuer
metadata:
name: letsencrypt-argocd
namespace: argocd
spec:
# ACME issuer configuration
# `email` - the email address to be associated with the ACME account (make sure it's a valid one)
# `server` - the URL used to access the ACME servers directory endpoint
# `privateKeySecretRef` - Kubernetes Secret to store the automatically generated ACME account private key
acme:
email: developer@kemkas.hu
server: https://acme-v02.api.letsencrypt.org/directory
privateKeySecretRef:
name: letsencrypt-argocd-private-key
solvers:
# Use the HTTP-01 challenge provider
- http01:
ingress:
class: nginx
+18
View File
@@ -0,0 +1,18 @@
controller:
replicaCount: 1 #reduced to 1 to save costs
# resources:
# requests:
# cpu: 0
# memory: 90Mi
service:
type: LoadBalancer
annotations:
# Enable proxy protocol
service.beta.kubernetes.io/do-loadbalancer-enable-proxy-protocol: "true"
# Specify whether the DigitalOcean Load Balancer should pass encrypted data to backend droplets
service.beta.kubernetes.io/do-loadbalancer-tls-passthrough: "true"
# Will add custom configuration options to Nginx https://kubernetes.github.io/ingress-nginx/user-guide/nginx-configuration/configmap/
config:
use-proxy-protocol: "true"
+77
View File
@@ -0,0 +1,77 @@
apiVersion: apps/v1
kind: Deployment
metadata:
name: kemkas
namespace: kemkas
labels:
app: kemkas
spec:
replicas: 1
selector:
matchLabels:
app: kemkas
template:
metadata:
name: kemkas
labels:
app: kemkas
spec:
containers:
- name: kemkas
image: registry.digitalocean.com/kemkas/kemkas:45914c78
imagePullPolicy: IfNotPresent
ports:
- containerPort: 8080
env:
- name: Email__DomainName
value: mail.kemkas.hu
- name: Email__ApiKey
valueFrom:
secretKeyRef:
name: kemkas-envs
key: email--api-key
- name: ConnectionStrings__DefaultConnection
valueFrom:
secretKeyRef:
name: kemkas-envs
key: connection-strings--default-connection
- name: Authentication__Google__ClientId
valueFrom:
secretKeyRef:
name: kemkas-envs
key: authentication--google--client-id
- name: Authentication__Google__ClientSecret
valueFrom:
secretKeyRef:
name: kemkas-envs
key: authentication--google--client-secret
- name: Authentication__Facebook__ClientId
valueFrom:
secretKeyRef:
name: kemkas-envs
key: authentication--facebook--client-id
- name: Authentication__Facebook__ClientSecret
valueFrom:
secretKeyRef:
name: kemkas-envs
key: authentication--facebook--client-secret
- name: Authentication__Discord__ClientId
valueFrom:
secretKeyRef:
name: kemkas-envs
key: authentication--discord--client-id
- name: Authentication__Discord__ClientSecret
valueFrom:
secretKeyRef:
name: kemkas-envs
key: authentication--discord--client-secret
resources:
requests:
cpu: 100m
memory: 100M
limits:
cpu: 1000m
memory: 500M
restartPolicy: Always
+16
View File
@@ -0,0 +1,16 @@
apiVersion: external-secrets.io/v1beta1
kind: ExternalSecret
metadata:
name: kemkas-external-secrets
namespace: kemkas
spec:
refreshInterval: 1h
secretStoreRef:
name: kemkas-secret-store
kind: SecretStore
target:
name: kemkas-envs
creationPolicy: Owner
dataFrom:
- extract:
key: kemkas-app
+26
View File
@@ -0,0 +1,26 @@
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: ingress-kemkas
namespace: kemkas
annotations:
# nginx.ingress.kubernetes.io/force-ssl-redirect: "true"
# nginx.ingress.kubernetes.io/backend-protocol: "HTTP"
cert-manager.io/issuer: letsencrypt-kemkas
spec:
ingressClassName: nginx
rules:
- http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: kemkas-service
port:
number: 8080
host: dev.kemkas.hu
tls:
- hosts:
- dev.kemkas.hu
secretName: letsencrypt-kemkas
+15
View File
@@ -0,0 +1,15 @@
apiVersion: v1
kind: Service
metadata:
name: kemkas-service
namespace: kemkas
labels:
app: kemkas
spec:
selector:
app: kemkas
type: ClusterIP
ports:
- protocol: TCP
port: 8080
targetPort: 8080
+20
View File
@@ -0,0 +1,20 @@
apiVersion: cert-manager.io/v1
kind: Issuer
metadata:
name: letsencrypt-kemkas
namespace: kemkas
spec:
# ACME issuer configuration
# `email` - the email address to be associated with the ACME account (make sure it's a valid one)
# `server` - the URL used to access the ACME servers directory endpoint
# `privateKeySecretRef` - Kubernetes Secret to store the automatically generated ACME account private key
acme:
email: developer@kemkas.hu
server: https://acme-v02.api.letsencrypt.org/directory
privateKeySecretRef:
name: letsencrypt-kemkas-private-key
solvers:
# Use the HTTP-01 challenge provider
- http01:
ingress:
class: nginx