feat(ingress): Add additional traefik for internal only access

A new traefik deployment has been added, and two ingressclasses have been set for the new instance, as well as the previous one. This allows the network to be split in two, one for external access and another for internal access. Each traefik deployment is connected to a loadbalancer requesting the IP necessary for each type of access.
This commit is contained in:
Tanguy Herbron 2022-11-20 03:38:22 +01:00
parent aa9e372c98
commit 0a41373688
12 changed files with 181 additions and 49 deletions

View File

@ -1,8 +1,10 @@
# K3s cluster
/!\ CHECK PORT RULES FOR EXPOSING INTERNAL SERVICES
| Name | Usage | Accessibility | Host | DB type | Additional data | Backup configuration | Loki integration | Prometheus integration | Status |
|-------------------------|--------------------------------------|---------------|--------------|------------|----------------------|----------------------|------------------|------------------------|-----------------------------------|
| Traefik | Reverse proxy and load balancer | Public* | Socrates | - | - | - | Configured | Configured | Completed |
| Traefik | Reverse proxy and load balancer | Public* | Socrates | - | - | - | Configured | Configured | Completed<sup>5</sup> |
| Vaultwarden | Password manager | Public | Pythagoras-b | MariaDB | - | 4AM K8s CronJob | Configured | Not available | Completed |
| Gitlab | Version control system | Public | Pythagoras-b | PostgreSQL | User created content | 5AM internal CronJob | Configured | Configured | Completed<sup>4</sup> |
| Prometheus | Metrics aggregator | Private | Pythagoras-b | TBD | - | Not configured | Configured | Configured | Partial |
@ -32,6 +34,7 @@
<sup>2</sup> Missing configuration for NAS volume mounting (over network)<br>
<sup>3</sup> Missing Longhorn scheduling for saving media_store and secret management<br>
<sup>4</sup> Backup management is not handled by k3s but by an internal cronjob rule (Change image name when putting to production)<br>
<sup>5</sup> Missing dashboard configuration<br>
## Backup management
### Databases
@ -57,7 +60,7 @@ longhorn
- Change host/deployment specific variables to use environment variables
- Write CI/CD pipeline to create environment loaded files
- Write CI/CD pipeline to deploy cluster
- ~~Setup internal traefik with nodeport as reverse proxy for internal only services~~ Done through internal LB
- ~~Setup internal traefik with nodeport as reverse proxy for internal only services~~ Done through double ingress class and LB
- ~~Setup DB container sidecars for automated backups to Longhorn volume~~
- Setup secrets configuration through CI/CD variable injection
- Explore permission issues when issuing OVH API keys (not working for wildcard and `beta.halia.dev` subdomain)
@ -103,5 +106,11 @@ This ansible script could create one (or more) additional client(s) depending on
Cf : https://docs.k3s.io/advanced#auto-deploying-manifests
### Development domains
To access a service publicly when developping, the domain name should be *.beta.halia.dev
To access a service publicly when developing, the domain name should be *.beta.halia.dev
To only expose a service internally, the domain name should be *.k3s.beta
### Ingresses
To split between external and internal services, two traefik ingresses are implemented through the `ingressclass` annotation.
`traefik-external` will only allow external access to a given service, while `traefik-internal` restrict to an internal only access.

View File

@ -26,7 +26,7 @@ items:
name: minecrafttcp
targetPort: "minecrafttcp"
protocol: TCP
- port: 80
- port: 80 # Change port here to accomodate for internal only services
name: web
targetPort: "web"
protocol: TCP

View File

@ -0,0 +1,146 @@
---
# Source: traefik/templates/deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: traefik-inter
labels:
app.kubernetes.io/name: traefik-inter
app.kubernetes.io/instance: traefik-inter
annotations:
spec:
replicas: 1
selector:
matchLabels:
app.kubernetes.io/name: traefik-inter
app.kubernetes.io/instance: traefik-inter
strategy:
type: RollingUpdate
rollingUpdate:
maxSurge: 1
maxUnavailable: 1
minReadySeconds: 0
template:
metadata:
annotations:
prometheus.io/scrape: "true"
prometheus.io/path: "/metrics"
prometheus.io/port: "9100"
labels:
app.kubernetes.io/name: traefik-inter
app.kubernetes.io/instance: traefik-inter
spec:
serviceAccountName: traefik
terminationGracePeriodSeconds: 60
hostNetwork: false
containers:
- image: "traefik:2.8.4"
imagePullPolicy: IfNotPresent
name: traefik-inter
resources:
readinessProbe:
httpGet:
path: /ping
port: 9000
failureThreshold: 1
initialDelaySeconds: 10
periodSeconds: 10
successThreshold: 1
timeoutSeconds: 2
livenessProbe:
httpGet:
path: /ping
port: 9000
failureThreshold: 3
initialDelaySeconds: 10
periodSeconds: 10
successThreshold: 1
timeoutSeconds: 2
ports:
- name: "admin"
containerPort: 8080
protocol: "TCP"
- name: "metrics"
containerPort: 9100
protocol: "TCP"
- name: "traefik"
containerPort: 9000
protocol: "TCP"
- name: "web"
containerPort: 8000
protocol: "TCP"
- name: "websecure"
containerPort: 8443
protocol: "TCP"
securityContext:
capabilities:
drop:
- ALL
readOnlyRootFilesystem: true
runAsGroup: 65532
runAsNonRoot: true
runAsUser: 65532
volumeMounts:
- name: data
mountPath: /certs
- name: tmp
mountPath: /tmp
args:
- "--global.checknewversion"
- "--entrypoints.admin.address=:8080/tcp"
- "--entrypoints.metrics.address=:9100/tcp"
- "--entrypoints.traefik.address=:9000/tcp"
- "--entrypoints.web.address=:8000/tcp"
- "--entrypoints.websecure.address=:8443/tcp"
- "--api.dashboard=true"
- "--api.insecure=true"
- "--ping=true"
- "--metrics.prometheus=true"
- "--metrics.prometheus.entrypoint=metrics"
- "--providers.kubernetescrd"
- "--providers.kubernetesingress"
- "--providers.kubernetescrd.ingressclass=traefik-inter"
- "--providers.kubernetesingress.ingressclass=traefik-inter"
- "--entrypoints.web.http.redirections.entryPoint.to=:443"
- "--entrypoints.web.http.redirections.entryPoint.scheme=https"
- "--log.level=DEBUG"
- "--accesslog=true"
- "--entrypoints.websecure.http.tls=true"
- "--entrypoints.websecure.http.tls.certresolver=letsencrypt"
- "--entrypoints.websecure.http.tls.domains[0].main=k3s.beta"
- "--entrypoints.websecure.http.tls.domains[0].sans=*.k3s.beta"
- "--certificatesresolvers.letsencrypt.acme.tlschallenge=true"
- "--certificatesresolvers.letsencrypt.acme.dnschallenge=true"
- "--certificatesresolvers.letsencrypt.acme.dnschallenge.provider=ovh"
- "--certificatesresolvers.letsencrypt.acme.dnschallenge.resolvers=1.1.1.1"
- "--certificatesresolvers.letsencrypt.acme.email=tanguy.herbron@outlook.com"
- "--certificatesresolvers.letsencrypt.acme.storage=/certs/acme.json"
env:
- name: OVH_APPLICATION_KEY
valueFrom:
secretKeyRef:
key: appKey
name: ovh-api-credentials
- name: OVH_APPLICATION_SECRET
valueFrom:
secretKeyRef:
key: appSecret
name: ovh-api-credentials
- name: OVH_CONSUMER_KEY
valueFrom:
secretKeyRef:
key: consumerKey
name: ovh-api-credentials
- name: OVH_ENDPOINT
valueFrom:
secretKeyRef:
key: endpoint
name: ovh-api-credentials
volumes:
- name: data
persistentVolumeClaim:
claimName: traefik-inter
- name: tmp
emptyDir: {}
securityContext:
fsGroup: 65532

View File

@ -0,0 +1,18 @@
---
# Source: traefik/templates/pvc.yaml
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: traefik-inter
annotations:
helm.sh/resource-policy: keep
labels:
app.kubernetes.io/name: traefik-inter
app.kubernetes.io/instance: traefik-inter
spec:
accessModes:
- "ReadWriteOnce"
resources:
requests:
storage: "128Mi"
storageClassName: "local-path"

View File

@ -10,22 +10,16 @@ items:
metadata:
name: traefik-internal
labels:
app.kubernetes.io/name: traefik-internal
helm.sh/chart: traefik-10.24.2
app.kubernetes.io/managed-by: Helm
app.kubernetes.io/instance: traefik
app.kubernetes.io/name: traefik-inter
app.kubernetes.io/instance: traefik-inter
annotations:
spec:
type: LoadBalancer
loadBalancerIP: 10.10.0.64
selector:
app.kubernetes.io/name: traefik
app.kubernetes.io/instance: traefik
app.kubernetes.io/name: traefik-inter
app.kubernetes.io/instance: traefik-inter
ports:
- port: 25565
name: minecrafttcp
targetPort: "minecrafttcp"
protocol: TCP
- port: 80
name: web
targetPort: "web"

View File

@ -1,22 +0,0 @@
---
# Source: traefik/templates/dashboard-hook-ingressroute.yaml
apiVersion: traefik.containo.us/v1alpha1
kind: IngressRoute
metadata:
name: traefik-dashboard
annotations:
helm.sh/hook: "post-install,post-upgrade"
labels:
app.kubernetes.io/name: traefik
helm.sh/chart: traefik-10.24.2
app.kubernetes.io/managed-by: Helm
app.kubernetes.io/instance: traefik
spec:
entryPoints:
- traefik
routes:
- match: PathPrefix(`/dashboard`) || PathPrefix(`/api`)
kind: Rule
services:
- name: api@internal
kind: TraefikService

View File

@ -1,13 +0,0 @@
apiVersion: traefik.containo.us/v1alpha1
kind: IngressRoute
metadata:
name: traefik-dashboard
spec:
entryPoints:
- websecure
routes:
- kind: Rule
match: Host(`traefik.k3s.beta`)
services:
- name: api@internal
kind: TraefikService