diff --git a/.gitea/workflows/ci.yaml b/.gitea/workflows/ci.yaml index 26dbe7e..f6eb457 100644 --- a/.gitea/workflows/ci.yaml +++ b/.gitea/workflows/ci.yaml @@ -18,16 +18,30 @@ jobs: - name: Build and push run: unset GITEA_TOKEN && build && push - deploy-prod: + deploy-prod-frostmoln: needs: build if: gitea.ref == 'refs/heads/master' runs-on: ubuntu-latest env: - BUILDTOOLS_CONTENT: ${{ secrets.BUILDTOOLS_CONTENT }} + BUILDTOOLS_CONTENT: ${{ secrets.BUILDTOOLS_FROSTMOLN_PRODUCTION }} GITEA_REPOSITORY: ${{ gitea.repository }} + FM_TENANT: 9ae61342-0f76-476f-8176-e46f6b0b0c32 environment: prod steps: - uses: actions/checkout@v7 - uses: buildtool/setup-buildtools-action@v1 - - name: Deploy - run: deploy prod + - name: Install fm + run: | + sudo install -d -m 0755 /etc/apt/keyrings + sudo curl -fsSL -o /etc/apt/keyrings/frostmoln.gpg https://get.frostmoln.cloud/deb/frostmoln.gpg + sudo curl -fsSL -o /etc/apt/sources.list.d/frostmoln.sources https://get.frostmoln.cloud/deb/frostmoln.sources + sudo apt-get update && sudo apt-get install -y fm + - name: Deploy to Frostmoln production + env: + FROSTMOLN_API_KEY: ${{ secrets.FROSTMOLN_PRODUCTION_DEPLOY_KEY }} + # The cluster API is private: the kubeconfig's exec plugin opens an fm + # tunnel on demand. fm reads the key from its config file, not the env. + run: | + fm auth api-key set "$FROSTMOLN_API_KEY" > /dev/null + fm kubernetes cluster kubeconfig ${{ vars.FROSTMOLN_PRODUCTION_CLUSTER_ID }} --exec --file "$RUNNER_TEMP/kubeconfig" + KUBECONFIG_CONTENT="$(cat "$RUNNER_TEMP/kubeconfig")" deploy prod-frostmoln -n dancefinder diff --git a/k8s/deploy.yaml b/k8s/deploy.yaml index 3f09556..af71570 100644 --- a/k8s/deploy.yaml +++ b/k8s/deploy.yaml @@ -21,6 +21,13 @@ spec: labels: app.kubernetes.io/name: geo-service spec: + imagePullSecrets: + - name: oci-registry + securityContext: + runAsNonRoot: true + runAsUser: 65534 + seccompProfile: + type: RuntimeDefault affinity: podAntiAffinity: preferredDuringSchedulingIgnoredDuringExecution: @@ -35,6 +42,10 @@ spec: topologyKey: kubernetes.io/hostname containers: - name: geo-service + securityContext: + allowPrivilegeEscalation: false + capabilities: + drop: ["ALL"] resources: limits: memory: "100Mi" @@ -43,8 +54,11 @@ spec: imagePullPolicy: Always image: ${IMAGE} ports: - - containerPort: 80 + - containerPort: 8080 name: http + env: + - name: PORT + value: "8080" envFrom: - secretRef: name: geo-service @@ -59,7 +73,7 @@ spec: - port: 80 name: http protocol: TCP - targetPort: 80 + targetPort: 8080 selector: app.kubernetes.io/name: geo-service type: ClusterIP diff --git a/k8s/secrets-prod-frostmoln.yaml b/k8s/secrets-prod-frostmoln.yaml new file mode 100644 index 0000000..73c80d1 --- /dev/null +++ b/k8s/secrets-prod-frostmoln.yaml @@ -0,0 +1,21 @@ +apiVersion: external-secrets.io/v1 +kind: ExternalSecret +metadata: + name: geo-service +spec: + refreshInterval: 1h + # The namespace's store (infra frostmoln/production/apps.tf); MAPS_API_KEY + # lives in the Frostmoln Secret "dancefinder", next to the API's settings + # (infra frostmoln/production/scripts/seed-app.sh). + secretStoreRef: + name: frostmoln + kind: SecretStore + target: + name: geo-service + template: + engineVersion: v2 + data: + MAPS_API_KEY: "{{ .MAPS_API_KEY }}" + dataFrom: + - extract: + key: dancefinder diff --git a/k8s/secrets.yaml b/k8s/secrets.yaml deleted file mode 100644 index ed155e5..0000000 --- a/k8s/secrets.yaml +++ /dev/null @@ -1,14 +0,0 @@ -apiVersion: external-secrets.io/v1 -kind: ExternalSecret -metadata: - name: geo-service -spec: - refreshInterval: 1h - secretStoreRef: - name: external-secrets - kind: ClusterSecretStore - target: - creationPolicy: Owner - dataFrom: - - extract: - key: applications/dancefinder/geo-service