diff --git a/.github/workflows/actions/docker-login/action.yml b/.github/workflows/actions/docker-login/action.yml new file mode 100644 index 0000000..e0ab972 --- /dev/null +++ b/.github/workflows/actions/docker-login/action.yml @@ -0,0 +1,17 @@ +name: Docker Login +description: Logs in to Docker Hub +inputs: + username: + description: 'Docker Hub username' + required: true + password: + description: 'Docker Hub password' + required: true +runs: + using: "composite" + steps: + - name: Login to Docker Hub + uses: docker/login-action@v3 + with: + username: ${{ inputs.username }} + password: ${{ inputs.password }} \ No newline at end of file diff --git a/.github/workflows/basic-system-information.yml b/.github/workflows/basic-system-information.yml new file mode 100644 index 0000000..3881e1f --- /dev/null +++ b/.github/workflows/basic-system-information.yml @@ -0,0 +1,40 @@ +name: Basic System Information +on: + workflow_dispatch: + +jobs: + Basic-system-information: + runs-on: mealcraft-runners + container: ubuntu:22.04 + steps: + - uses: actions/checkout@v4 + - name: hi + run: echo "hi" + - name: user + run: echo $USER + - name: home + run: echo $HOME + - name: pwd + run: pwd + - name: ls -la + run: ls -la + - name: Install kubectl + run: | + apt-get update + apt-get install -y ca-certificates curl + curl -LO "https://dl.k8s.io/release/$(curl -L -s https://dl.k8s.io/release/stable.txt)/bin/linux/amd64/kubectl" + install -m 0755 kubectl /usr/local/bin/kubectl + - name: Configure kubeconfig from runner SA + run: | + KUBE_HOST="https://$KUBERNETES_SERVICE_HOST:$KUBERNETES_SERVICE_PORT" + SA_TOKEN=$(cat /var/run/secrets/kubernetes.io/serviceaccount/token) + CA_CERT=/var/run/secrets/kubernetes.io/serviceaccount/ca.crt + NAMESPACE=$(cat /var/run/secrets/kubernetes.io/serviceaccount/namespace) + + kubectl config set-cluster k8s --server="$KUBE_HOST" --certificate-authority="$CA_CERT" + kubectl config set-credentials sa --token="$SA_TOKEN" + kubectl config set-context sa-context --cluster=k8s --user=sa --namespace="$NAMESPACE" + kubectl config use-context sa-context + + - name: kubectl test + run: kubectl get pods -A \ No newline at end of file diff --git a/README.md b/README.md index 758018a..fb5b8ea 100644 --- a/README.md +++ b/README.md @@ -7,7 +7,11 @@ TODO: - [x] Download next js - [x] Aws terraform plan and apply configured - [] Deploy into my new k8s - - [] + - [] deploy docker registry credentials + - [] deploy storageclass + - [] deloy traefik customised + - [] deploy who-am-i + - Traefik certs change to staging - May need to move aws terraform here too - [] Deploy into my dockercontainer new image \ No newline at end of file diff --git a/github_runner/install/install_arc.sh b/github_runner/install/install_arc.sh index 0f74b20..8c60e57 100644 --- a/github_runner/install/install_arc.sh +++ b/github_runner/install/install_arc.sh @@ -11,27 +11,56 @@ set -ex # sudo usermod -aG microk8s $USER # sudo chown -f -R $USER ~/.kube -helm uninstall arc -n arc-systems || true +# helm uninstall arc -n arc-systems || true -echo "=== Install ARC Scale Set Controller ===" -helm install arc \ - --namespace arc-systems \ - --create-namespace \ - oci://ghcr.io/actions/actions-runner-controller-charts/gha-runner-scale-set-controller +# echo "=== Install ARC Scale Set Controller ===" +# helm install arc \ +# --namespace arc-systems \ +# --create-namespace \ +# oci://ghcr.io/actions/actions-runner-controller-charts/gha-runner-scale-set-controller -helm uninstall mealcraft-runners -n arc-systems || true +# helm uninstall mealcraft-runners -n arc-systems || true -helm install mealcraft-runners \ - --namespace arc-systems \ - --create-namespace \ - --set runnerScaleSetName="mealcraft-runners" \ - --set githubConfigUrl="https://github.com/MealCraft" \ - --set githubConfigSecret.name="github-secret" \ - --set githubConfigSecret.github_token="$GITHUB_PAT" \ - --set containerMode.type="kubernetes" \ - --set containerMode.kubernetesModeDefaultContainer.image="ubuntu:22.04" \ - --set containerMode.kubernetesModeWorkVolumeClaim.accessModes[0]="ReadWriteOnce" \ - --set containerMode.kubernetesModeWorkVolumeClaim.storageClassName="microk8s-hostpath" \ - --set containerMode.kubernetesModeWorkVolumeClaim.resources.requests.storage="1Gi" \ - --set runnerLabels[0]="mealcraft" \ - oci://ghcr.io/actions/actions-runner-controller-charts/gha-runner-scale-set +# helm install mealcraft-runners \ +# --namespace arc-systems \ +# --create-namespace \ +# --set runnerScaleSetName="mealcraft-runners" \ +# --set githubConfigUrl="https://github.com/MealCraft" \ +# --set githubConfigSecret.name="github-secret" \ +# --set githubConfigSecret.github_token="$GITHUB_PAT" \ +# --set containerMode.type="kubernetes" \ +# --set containerMode.kubernetesModeDefaultContainer.image="ubuntu:22.04" \ +# --set containerMode.kubernetesModeWorkVolumeClaim.accessModes[0]="ReadWriteOnce" \ +# --set containerMode.kubernetesModeWorkVolumeClaim.storageClassName="microk8s-hostpath" \ +# --set containerMode.kubernetesModeWorkVolumeClaim.resources.requests.storage="1Gi" \ +# --set runnerLabels[0]="mealcraft" \ +# oci://ghcr.io/actions/actions-runner-controller-charts/gha-runner-scale-set + +echo "=== Applying RBAC for runner ===" + +microk8s kubectl apply -f - <<'EOF' +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: arc-runner-readonly +rules: + - apiGroups: [""] + resources: ["pods"] + verbs: ["get", "list", "watch"] + +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + name: arc-runner-readonly-binding +subjects: + - kind: ServiceAccount + name: mealcraft-runners + namespace: arc-systems +roleRef: + kind: ClusterRole + name: arc-runner-readonly + apiGroup: rbac.authorization.k8s.io +EOF + +echo "=== RBAC Applied Successfully ===" diff --git a/traefik/Dockerfile b/traefik/Dockerfile new file mode 100644 index 0000000..8bc3e79 --- /dev/null +++ b/traefik/Dockerfile @@ -0,0 +1,6 @@ +FROM traefik:v2.10 +RUN touch /log-file.log +COPY certificates/ /etc/traefik/certs/ +COPY ./traefik-dynamic.yaml ./etc/traefik/traefik-dynamic.yaml +COPY ./users ./etc/traefik/users +COPY ./traefik.yaml ./etc/traefik/traefik.yaml \ No newline at end of file diff --git a/traefik/README.md b/traefik/README.md new file mode 100644 index 0000000..4d97a8d --- /dev/null +++ b/traefik/README.md @@ -0,0 +1,3 @@ +# edge-router +One router to rule them all. Currently everything goes through 'edge-router' to work out where to go. + diff --git a/traefik/certificates/generate-wildcard-certificate.sh b/traefik/certificates/generate-wildcard-certificate.sh new file mode 100644 index 0000000..b55845a --- /dev/null +++ b/traefik/certificates/generate-wildcard-certificate.sh @@ -0,0 +1,37 @@ +#!/usr/bin/env bash + +# print usage +DOMAIN=$1 +if [ -z "$1" ]; then + + echo "USAGE: $0 domain.lan" + echo "" + echo "This will generate a non-secure self-signed wildcard certificate for given domain." + echo "This should only be used in a development environment." + exit +fi + +# Add wildcard +WILDCARD="*.$DOMAIN" + +# Set our CSR variables +SUBJ=" +C=US +ST=NY +O=Local Developement +localityName=Local Developement +commonName=$WILDCARD +organizationalUnitName=Local Developement +emailAddress=junte.kim@mealcraft.com +" + +# Generate our Private Key, CSR and Certificate +openssl genrsa -out "$DOMAIN.key" 2048 +openssl req -new -subj "$(echo -n "$SUBJ" | tr "\n" "/")" -key "$DOMAIN.key" -out "$DOMAIN.csr" +openssl x509 -req -days 3650 -in "$DOMAIN.csr" -signkey "$DOMAIN.key" -out "$DOMAIN.crt" +rm "$DOMAIN.csr" + +echo "" +echo "Next manual steps:" +echo "- Use $DOMAIN.crt and $DOMAIN.key to configure Apache/nginx" +echo "- Import $DOMAIN.crt into Chrome settings: chrome://settings/certificates > tab 'Authorities'" diff --git a/traefik/docker-registry-credentials/docker-credentials.yml b/traefik/docker-registry-credentials/docker-credentials.yml new file mode 100644 index 0000000..7b7b9db --- /dev/null +++ b/traefik/docker-registry-credentials/docker-credentials.yml @@ -0,0 +1,8 @@ +apiVersion: v1 +kind: Secret +metadata: + name: registrypullsecret + namespace: default +data: + .dockerconfigjson: ewoJImF1dGhzIjogewoJCSJodHRwczovL2luZGV4LmRvY2tlci5pby92MS8iOiB7CgkJCSJhdXRoIjogImEybHRhblZ1ZEdVNlpHTnJjbDl3WVhSZmJVdFNibkJ0TVZselJVOHRSRU5PVnpNelQwcG5hVGQ0WkdkQiIKCQl9Cgl9Cn0= +type: kubernetes.io/dockerconfigjson diff --git a/traefik/edge-router/metallb-system.yaml b/traefik/edge-router/metallb-system.yaml new file mode 100644 index 0000000..1539a61 --- /dev/null +++ b/traefik/edge-router/metallb-system.yaml @@ -0,0 +1,12 @@ +apiVersion: v1 +kind: ConfigMap +metadata: + namespace: metallb-system + name: config +data: + config: | + address-pools: + - name: default + protocol: layer2 + addresses: + - 192.168.1.200-192.168.1.210 \ No newline at end of file diff --git a/traefik/edge-router/middleware.yaml b/traefik/edge-router/middleware.yaml new file mode 100644 index 0000000..4ba3ac7 --- /dev/null +++ b/traefik/edge-router/middleware.yaml @@ -0,0 +1,7 @@ +apiVersion: traefik.io/v1alpha1 +kind: Middleware +metadata: + name: test-auth +spec: + basicAuth: + secret: authsecret \ No newline at end of file diff --git a/traefik/edge-router/pvc.yaml b/traefik/edge-router/pvc.yaml new file mode 100644 index 0000000..4414bad --- /dev/null +++ b/traefik/edge-router/pvc.yaml @@ -0,0 +1,12 @@ +apiVersion: v1 +kind: PersistentVolumeClaim +metadata: + name: certs-pvc +spec: + accessModes: + - ReadWriteMany + storageClassName: local-storage + resources: + requests: + storage: 1Mi + volumeName: certs-pv \ No newline at end of file diff --git a/traefik/edge-router/secret-dashboard.yml b/traefik/edge-router/secret-dashboard.yml new file mode 100644 index 0000000..e88dc1f --- /dev/null +++ b/traefik/edge-router/secret-dashboard.yml @@ -0,0 +1,9 @@ +apiVersion: v1 +kind: Secret +metadata: + name: authsecret + namespace: default +data: + users: | + anVudGUua2ltOiRhcHIxJFpBeUJnaVRiJHlJQXlNNE1XQVNlMkg4dEVMMVpIcDEK + Cg== \ No newline at end of file diff --git a/traefik/edge-router/traefik-deployment.yml b/traefik/edge-router/traefik-deployment.yml new file mode 100644 index 0000000..1775c45 --- /dev/null +++ b/traefik/edge-router/traefik-deployment.yml @@ -0,0 +1,81 @@ +apiVersion: v1 +kind: ServiceAccount +metadata: + namespace: default + name: traefik-ingress-controller + +--- + +kind: Deployment +apiVersion: apps/v1 +metadata: + name: traefik-deployment + labels: + app: traefik + +spec: + replicas: 1 + selector: + matchLabels: + app: traefik + template: + metadata: + labels: + app: traefik + spec: + serviceAccountName: traefik-ingress-controller + containers: + - name: traefik + image: traefik:v2.10 + args: + - --api.insecure + - --accesslog=True + - --entrypoints.web.Address=:80 + - --entrypoints.websecure.Address=:443 + - --providers.kubernetescrd + - --api.dashboard + - --serverstransport.insecureskipverify=true + # TLS (HTTPS) + - "--certificatesresolvers.myresolver.acme.dnschallenge=true" + - "--certificatesresolvers.myresolver.acme.httpChallenge=false" + - "--certificatesresolvers.myresolver.acme.tlsChallenge=false" + - "--certificatesresolvers.myresolver.acme.dnschallenge.provider=route53" + - "--certificatesresolvers.myresolver.acme.email=junte.kim@mealcraft.com" + - "--certificatesresolvers.myresolver.acme.storage=/certs/acme.json" + - "--certificatesresolvers.myresolver.acme.httpChallenge.entryPoint=web" + - "--entrypoints.web.http.redirections.entrypoint.to=websecure" + - "--entrypoints.web.http.redirections.entrypoint.scheme=https" + - "--entrypoints.websecure.address=:443" + - "--providers.kubernetescrd.allowexternalnameservices=true" + env: + - name: AWS_ACCESS_KEY_ID + valueFrom: + secretKeyRef: + name: aws-secrets + key: AWS_ACCESS_KEY_ID + - name: AWS_SECRET_ACCESS_KEY + valueFrom: + secretKeyRef: + name: aws-secrets + key: AWS_SECRET_ACCESS_KEY + - name: AWS_REGION + valueFrom: + secretKeyRef: + name: aws-secrets + key: AWS_REGION + ports: + - name: web + containerPort: 80 + - name: admin + containerPort: 8080 + - name: websecure + containerPort: 443 + volumeMounts: + - name: cert-volume + mountPath: /certs + imagePullSecrets: + - name: registrypullsecret + volumes: + - name: cert-volume + persistentVolumeClaim: + claimName: certs-pvc \ No newline at end of file diff --git a/traefik/edge-router/traefik-ingressroute.yml b/traefik/edge-router/traefik-ingressroute.yml new file mode 100644 index 0000000..1c35140 --- /dev/null +++ b/traefik/edge-router/traefik-ingressroute.yml @@ -0,0 +1,22 @@ +apiVersion: traefik.io/v1alpha1 +kind: IngressRoute +metadata: + name: dashboard + namespace: default +spec: + entryPoints: + - websecure + routes: + - match: Host(`www.traefik.mealcraft.com`, `traefik.mealcraft.com`) && PathPrefix(`/api`, `/dashboard`) + kind: Rule + middlewares: + - name: test-auth + services: + - name: traefik + port: 8080 + tls: + certResolver: myresolver + domains: + - main: traefik.mealcraft.com + sans: + - '*.traefik.mealcraft.com' \ No newline at end of file diff --git a/traefik/edge-router/traefik-services.yml b/traefik/edge-router/traefik-services.yml new file mode 100644 index 0000000..6e7935f --- /dev/null +++ b/traefik/edge-router/traefik-services.yml @@ -0,0 +1,19 @@ +apiVersion: v1 +kind: Service +metadata: + name: traefik + +spec: + type: LoadBalancer + ports: + - protocol: TCP + name: web + port: 80 + - protocol: TCP + name: websecure + port: 443 + - protocol: TCP + name: admin + port: 8080 + selector: + app: traefik \ No newline at end of file diff --git a/traefik/storageclass/certs-pv.yaml b/traefik/storageclass/certs-pv.yaml new file mode 100644 index 0000000..3edc8bf --- /dev/null +++ b/traefik/storageclass/certs-pv.yaml @@ -0,0 +1,24 @@ +apiVersion: v1 +kind: PersistentVolume +metadata: + name: certs-pv +spec: + capacity: + storage: 1Mi + volumeMode: Filesystem + accessModes: + - ReadWriteMany + persistentVolumeReclaimPolicy: Retain + storageClassName: local-storage + local: + path: /home/kimjunte/k8s_storage/certs + nodeAffinity: + required: + nodeSelectorTerms: + - matchExpressions: + - key: kubernetes.io/hostname + operator: In + values: + - gpd + + \ No newline at end of file diff --git a/traefik/storageclass/storageclass.yaml b/traefik/storageclass/storageclass.yaml new file mode 100644 index 0000000..2fb0673 --- /dev/null +++ b/traefik/storageclass/storageclass.yaml @@ -0,0 +1,6 @@ +apiVersion: storage.k8s.io/v1 +kind: StorageClass +metadata: + name: local-storage +provisioner: kubernetes.io/no-provisioner +volumeBindingMode: WaitForFirstConsumer \ No newline at end of file diff --git a/traefik/traefik-dynamic.yaml b/traefik/traefik-dynamic.yaml new file mode 100644 index 0000000..3e704b1 --- /dev/null +++ b/traefik/traefik-dynamic.yaml @@ -0,0 +1,34 @@ +tls: + stores: + default: + defaultCertificate: + certFile: "/etc/traefik/certs/mealcraft.com.crt" + keyFile: "/etc/traefik/certs/mealcraft.com.key" + options: + default: + minVersion: "VersionTLS13" + +# Solution found here for http to https => https://community.traefik.io/t/global-http-to-https-redirect-in-v2/1658 + +http: + routers: + http-catchall: + rule: "hostregexp(`{host:.+}`)" + entryPoints: + - "web" + middlewares: + - "redirect-to-https@file" + service: "never-called" + middlewares: + redirect-to-https: + redirectScheme: + scheme: "https" + permanent: true + dashboard-auth: + basicAuth: + usersFile: "/etc/traefik/users" + services: + never-called: + loadbalancer: + servers: + url: "http://192.168.0.1" \ No newline at end of file diff --git a/traefik/traefik.yaml b/traefik/traefik.yaml new file mode 100644 index 0000000..3262a8a --- /dev/null +++ b/traefik/traefik.yaml @@ -0,0 +1,41 @@ +log: + level: DEBUG + filePath: /log-file.log + format: json + +accessLog: {} +# certificatesResolvers: +# myresolver: +# acme: +# email: junte.kim@mealcraft.com +# # Mount a pvc to this location to not do let's encrypt everytime +# storage: /shared/acme.json +# httpChallenge: +# # used during the challenge +# entryPoint: web +# tlsChallenge: {} + +# tls: +# certificates: +# - certFile: /etc/traefik/certs/mealcraft.com.crt +# keyFile: /etc/traefik/certs/mealcraft.com.key + +entryPoints: + web: + address: :80 + websecure: + address: :443 + +providers: + file: + filename: "/etc/traefik/traefik-dynamic.yaml" + watch: true + docker: + exposedByDefault: false + +api: + dashboard: true + +# needed to make oauth work +serversTransport: + insecureSkipVerify: true \ No newline at end of file diff --git a/traefik/users b/traefik/users new file mode 100644 index 0000000..d14949a --- /dev/null +++ b/traefik/users @@ -0,0 +1,2 @@ +# http://aspirine.org/htpasswd_en.html MD5(APR) +junte.kim:$apr1$9MqwpTdt$Gw2uJwNq1qyfMRLIwBvLZ/ \ No newline at end of file diff --git a/traefik/who-am-i/whoami-deployment.yml b/traefik/who-am-i/whoami-deployment.yml new file mode 100644 index 0000000..289e7c2 --- /dev/null +++ b/traefik/who-am-i/whoami-deployment.yml @@ -0,0 +1,24 @@ +kind: Deployment +apiVersion: apps/v1 +metadata: + namespace: default + name: whoami + labels: + app: whoami + +spec: + replicas: 2 + selector: + matchLabels: + app: whoami + template: + metadata: + labels: + app: whoami + spec: + containers: + - name: whoami + image: traefik/whoami + ports: + - name: web + containerPort: 80 \ No newline at end of file diff --git a/traefik/who-am-i/whoami-ingressroute.yml b/traefik/who-am-i/whoami-ingressroute.yml new file mode 100644 index 0000000..9a980f7 --- /dev/null +++ b/traefik/who-am-i/whoami-ingressroute.yml @@ -0,0 +1,20 @@ +apiVersion: traefik.io/v1alpha1 +kind: IngressRoute +metadata: + name: simpleingressroute + namespace: default +spec: + entryPoints: + - websecure + routes: + - match: "Host(`www.whoami.mealcraft.com`, `whoami.mealcraft.com`)" + kind: Rule + services: + - name: whoami + port: 80 + tls: + certResolver: myresolver + domains: + - main: whoami.mealcraft.com + sans: + - '*.whoami.mealcraft.com' \ No newline at end of file diff --git a/traefik/who-am-i/whoami-service.yml b/traefik/who-am-i/whoami-service.yml new file mode 100644 index 0000000..e369c53 --- /dev/null +++ b/traefik/who-am-i/whoami-service.yml @@ -0,0 +1,12 @@ +apiVersion: v1 +kind: Service +metadata: + name: whoami + +spec: + ports: + - protocol: TCP + name: web + port: 80 + selector: + app: whoami \ No newline at end of file