First commit

This commit is contained in:
sttlab
2026-05-03 11:54:33 +00:00
commit 0d1e5dd9b8
7 changed files with 766 additions and 0 deletions
+15
View File
@@ -0,0 +1,15 @@
{
"permissions": {
"allow": [
"Bash(kubectl describe *)",
"Bash(helm show *)",
"Bash(kubectl get *)",
"Bash(kubectl logs *)",
"Bash(curl -s -o /dev/null -w \"%{http_code} %{content_type} %{size_download}\\\\n\" -H \"Accept-Encoding: gzip\" http://10.42.0.44:8080/styles.cc735d5acda5c758.css)",
"Bash(curl -s -o /dev/null -w \"%{http_code} %{content_type} %{size_download}\\\\n\" -H \"Accept-Encoding: gzip\" -H \"X-Forwarded-Proto: https\" http://10.42.0.44:8080/styles.cc735d5acda5c758.css)",
"Bash(curl -sv http://10.42.0.44:8080/styles.cc735d5acda5c758.css)",
"Bash(curl -sk -o /dev/null -w \"%{http_code} %{content_type}\\\\n\" --resolve console.gravitee.sttlab.pc:443:192.168.1.18 https://console.gravitee.sttlab.pc/styles.cc735d5acda5c758.css)",
"Bash(kill %1)"
]
}
}
+296
View File
@@ -0,0 +1,296 @@
# Gravitee APIM OSS - prod-like single-node k3s deployment
# - Domain: gravitee.sttlab.pc
# - Ingress: nginx
# - TLS everywhere (ingress + internal component HTTPS)
# - Credentials sourced from pre-created secrets
adminAccountEnable: true
adminPasswordBcrypt: "${GRAVITEE_ADMIN_PASSWORD_BCRYPT}"
# External MongoDB — URI injected at runtime via GRAVITEE_MANAGEMENT/RATELIMIT_MONGODB_URI
# from the gravitee-mongodb-uri secret (see deployment.envFrom below)
mongo:
dbhost: mongodb.gravitee-apim.svc.cluster.local
dbname: gravitee
dbport: 27017
rsEnabled: false
# External Elasticsearch (HTTPS + basic auth)
# Password injected at runtime via env var from gravitee-es-master-credentials secret
es:
endpoints:
- https://gravitee-es-master.gravitee-apim.svc.cluster.local:9200
security:
enabled: true
username: elastic
password: ""
# ============================================================
# API Gateway (data plane) - 2 replicas
# ============================================================
gateway:
enabled: true
replicaCount: 2
# Mount CA bundle and internal server cert
extraVolumes: |
- name: gravitee-ca
secret:
secretName: gravitee-ca-tls
items:
- key: ca.crt
path: ca.crt
- name: gateway-internal-tls
secret:
secretName: gateway-internal-tls
- name: es-truststore
secret:
secretName: elasticsearch-tls
items:
- key: truststore.jks
path: truststore.jks
extraVolumeMounts: |
- name: gravitee-ca
mountPath: /run/secrets/ca
readOnly: true
- name: gateway-internal-tls
mountPath: /run/secrets/tls
readOnly: true
- name: es-truststore
mountPath: /run/secrets/truststore
readOnly: true
deployment:
envFrom:
- secretRef:
name: gravitee-mongodb-uri
env:
- name: GRAVITEE_REPORTERS_ELASTICSEARCH_SECURITY_PASSWORD
valueFrom:
secretKeyRef:
name: gravitee-es-master-credentials
key: password
- name: JKS_PASSWORD
valueFrom:
secretKeyRef:
name: gravitee-jks-password
key: password
- name: JAVA_OPTS
value: "-Djavax.net.ssl.trustStore=/run/secrets/truststore/truststore.jks -Djavax.net.ssl.trustStorePassword=$(JKS_PASSWORD)"
# Enable HTTPS on the gateway listener (port 8082)
ssl:
enabled: true
keystore:
type: pkcs12
path: /run/secrets/tls/keystore.p12
password: "${JKS_PASSWORD}"
resources:
requests:
cpu: 200m
memory: 512Mi
limits:
cpu: 1000m
memory: 1Gi
service:
type: ClusterIP
externalPort: 443
internalPort: 8082
ingress:
enabled: true
ingressClassName: nginx
annotations:
# Gateway already terminates TLS internally; nginx forwards as HTTPS
nginx.ingress.kubernetes.io/backend-protocol: "HTTPS"
nginx.ingress.kubernetes.io/proxy-ssl-verify: "off"
hosts:
- gateway.gravitee.sttlab.pc
path: /
pathType: Prefix
tls:
- hosts:
- gateway.gravitee.sttlab.pc
secretName: gateway-tls
autoscaling:
enabled: false
# ============================================================
# Management API (control plane) - 1 replica
# ============================================================
api:
enabled: true
replicaCount: 1
extraVolumes: |
- name: gravitee-ca
secret:
secretName: gravitee-ca-tls
items:
- key: ca.crt
path: ca.crt
- name: api-internal-tls
secret:
secretName: api-internal-tls
- name: es-truststore
secret:
secretName: elasticsearch-tls
items:
- key: truststore.jks
path: truststore.jks
extraVolumeMounts: |
- name: gravitee-ca
mountPath: /run/secrets/ca
readOnly: true
- name: api-internal-tls
mountPath: /run/secrets/tls
readOnly: true
- name: es-truststore
mountPath: /run/secrets/truststore
readOnly: true
deployment:
envFrom:
- secretRef:
name: gravitee-mongodb-uri
- secretRef:
name: gravitee-jwt
env:
- name: GRAVITEE_ADMIN_PASSWORD_BCRYPT
valueFrom:
secretKeyRef:
name: gravitee-admin
key: admin-password-bcrypt
- name: GRAVITEE_ANALYTICS_ELASTICSEARCH_SECURITY_PASSWORD
valueFrom:
secretKeyRef:
name: gravitee-es-master-credentials
key: password
- name: JKS_PASSWORD
valueFrom:
secretKeyRef:
name: gravitee-jks-password
key: password
- name: JAVA_OPTS
value: "-Djavax.net.ssl.trustStore=/run/secrets/truststore/truststore.jks -Djavax.net.ssl.trustStorePassword=$(JKS_PASSWORD)"
# Enable HTTPS on Management API + Portal API listeners
http:
services:
core:
http:
enabled: true
port: 18083
host: 0.0.0.0
ssl:
enabled: true
keystore:
type: pkcs12
path: /run/secrets/tls/keystore.p12
password: "${JKS_PASSWORD}"
resources:
requests:
cpu: 200m
memory: 768Mi
limits:
cpu: 1000m
memory: 2Gi
ingress:
management:
enabled: true
ingressClassName: nginx
annotations:
nginx.ingress.kubernetes.io/backend-protocol: "HTTPS"
nginx.ingress.kubernetes.io/proxy-ssl-verify: "off"
path: /management
pathType: Prefix
hosts:
- api.gravitee.sttlab.pc
tls:
- hosts:
- api.gravitee.sttlab.pc
secretName: api-tls
portal:
enabled: true
ingressClassName: nginx
annotations:
nginx.ingress.kubernetes.io/backend-protocol: "HTTPS"
nginx.ingress.kubernetes.io/proxy-ssl-verify: "off"
path: /portal
pathType: Prefix
hosts:
- api.gravitee.sttlab.pc
tls:
- hosts:
- api.gravitee.sttlab.pc
secretName: api-tls
# ============================================================
# Management UI (Console) - 1 replica
# ============================================================
ui:
enabled: true
replicaCount: 1
resources:
requests:
cpu: 100m
memory: 128Mi
limits:
cpu: 500m
memory: 256Mi
ingress:
enabled: true
ingressClassName: nginx
annotations:
nginx.ingress.kubernetes.io/use-regex: "true"
hosts:
- console.gravitee.sttlab.pc
path: /(.*)
pathType: ImplementationSpecific
tls:
- hosts:
- console.gravitee.sttlab.pc
secretName: console-tls
# ============================================================
# Developer Portal UI - 1 replica
# ============================================================
portal:
enabled: true
replicaCount: 1
resources:
requests:
cpu: 100m
memory: 128Mi
limits:
cpu: 500m
memory: 256Mi
ingress:
enabled: true
ingressClassName: nginx
annotations:
nginx.ingress.kubernetes.io/use-regex: "true"
nginx.ingress.kubernetes.io/rewrite-target: /$1
hosts:
- portal.gravitee.sttlab.pc
path: /(.*)
pathType: ImplementationSpecific
tls:
- hosts:
- portal.gravitee.sttlab.pc
secretName: portal-tls
+202
View File
@@ -0,0 +1,202 @@
# cert-manager configuration for Gravitee APIM
# Self-signed CA + namespace-scoped Issuer
#
# To switch to HashiCorp Vault later:
# 1. Replace `gravitee-ca-issuer` (Issuer kind: CA) with a Vault Issuer:
# apiVersion: cert-manager.io/v1
# kind: Issuer
# metadata: {name: gravitee-ca-issuer, namespace: gravitee-apim}
# spec:
# vault:
# server: https://vault.sttlab.pc:8200
# path: pki/sign/gravitee
# auth: { kubernetes: { ... } }
# 2. Keep the Certificate resources below unchanged - they reference
# `gravitee-ca-issuer` by name, so the swap is transparent.
---
# Step 1: bootstrap a self-signed Issuer (only used to sign the CA cert)
apiVersion: cert-manager.io/v1
kind: Issuer
metadata:
name: gravitee-selfsigned-bootstrap
namespace: gravitee-apim
spec:
selfSigned: {}
---
# Step 2: create a CA certificate signed by the bootstrap issuer
apiVersion: cert-manager.io/v1
kind: Certificate
metadata:
name: gravitee-ca
namespace: gravitee-apim
spec:
isCA: true
commonName: gravitee-ca.sttlab.pc
secretName: gravitee-ca-tls
duration: 87600h # 10 years
privateKey:
algorithm: RSA
size: 4096
issuerRef:
name: gravitee-selfsigned-bootstrap
kind: Issuer
group: cert-manager.io
---
# Step 3: the actual CA Issuer used by all Gravitee certs
# This is the resource to replace when integrating Vault PKI later
apiVersion: cert-manager.io/v1
kind: Issuer
metadata:
name: gravitee-ca-issuer
namespace: gravitee-apim
spec:
ca:
secretName: gravitee-ca-tls
---
# ----------------------------
# Ingress certificates (one per public host)
# ----------------------------
apiVersion: cert-manager.io/v1
kind: Certificate
metadata:
name: console-tls
namespace: gravitee-apim
spec:
secretName: console-tls
dnsNames:
- console.gravitee.sttlab.pc
issuerRef:
name: gravitee-ca-issuer
kind: Issuer
---
apiVersion: cert-manager.io/v1
kind: Certificate
metadata:
name: portal-tls
namespace: gravitee-apim
spec:
secretName: portal-tls
dnsNames:
- portal.gravitee.sttlab.pc
issuerRef:
name: gravitee-ca-issuer
kind: Issuer
---
apiVersion: cert-manager.io/v1
kind: Certificate
metadata:
name: api-tls
namespace: gravitee-apim
spec:
secretName: api-tls
dnsNames:
- api.gravitee.sttlab.pc
issuerRef:
name: gravitee-ca-issuer
kind: Issuer
---
apiVersion: cert-manager.io/v1
kind: Certificate
metadata:
name: gateway-tls
namespace: gravitee-apim
spec:
secretName: gateway-tls
dnsNames:
- gateway.gravitee.sttlab.pc
issuerRef:
name: gravitee-ca-issuer
kind: Issuer
---
# ----------------------------
# Internal TLS server certs (cluster.local hostnames)
# ----------------------------
apiVersion: cert-manager.io/v1
kind: Certificate
metadata:
name: mongodb-tls
namespace: gravitee-apim
spec:
secretName: mongodb-tls
commonName: mongodb.gravitee-apim.svc.cluster.local
dnsNames:
- mongodb
- mongodb.gravitee-apim
- mongodb.gravitee-apim.svc
- mongodb.gravitee-apim.svc.cluster.local
- mongodb-0.mongodb-headless.gravitee-apim.svc.cluster.local
issuerRef:
name: gravitee-ca-issuer
kind: Issuer
---
apiVersion: cert-manager.io/v1
kind: Certificate
metadata:
name: elasticsearch-tls
namespace: gravitee-apim
spec:
secretName: elasticsearch-tls
commonName: gravitee-es-master.gravitee-apim.svc.cluster.local
dnsNames:
- gravitee-es-master
- gravitee-es-master.gravitee-apim
- gravitee-es-master.gravitee-apim.svc
- gravitee-es-master.gravitee-apim.svc.cluster.local
issuerRef:
name: gravitee-ca-issuer
kind: Issuer
keystores:
jks:
create: true
passwordSecretRef:
name: gravitee-jks-password
key: password
---
apiVersion: cert-manager.io/v1
kind: Certificate
metadata:
name: gateway-internal-tls
namespace: gravitee-apim
spec:
secretName: gateway-internal-tls
commonName: graviteeio-apim-gateway.gravitee-apim.svc.cluster.local
dnsNames:
- graviteeio-apim-gateway
- graviteeio-apim-gateway.gravitee-apim
- graviteeio-apim-gateway.gravitee-apim.svc
- graviteeio-apim-gateway.gravitee-apim.svc.cluster.local
- gateway.gravitee.sttlab.pc
issuerRef:
name: gravitee-ca-issuer
kind: Issuer
keystores:
pkcs12:
create: true
passwordSecretRef:
name: gravitee-jks-password
key: password
---
apiVersion: cert-manager.io/v1
kind: Certificate
metadata:
name: api-internal-tls
namespace: gravitee-apim
spec:
secretName: api-internal-tls
commonName: graviteeio-apim-api.gravitee-apim.svc.cluster.local
dnsNames:
- graviteeio-apim-api
- graviteeio-apim-api.gravitee-apim
- graviteeio-apim-api.gravitee-apim.svc
- graviteeio-apim-api.gravitee-apim.svc.cluster.local
- api.gravitee.sttlab.pc
issuerRef:
name: gravitee-ca-issuer
kind: Issuer
keystores:
pkcs12:
create: true
passwordSecretRef:
name: gravitee-jks-password
key: password
+90
View File
@@ -0,0 +1,90 @@
#!/usr/bin/env bash
# Deploy Gravitee APIM OSS on a single-node k3s cluster
# - Domain: *.gravitee.sttlab.pc
# - Ingress: nginx
# - TLS: cert-manager with namespace-scoped self-signed CA Issuer
# - Secrets: pre-created (run create-secrets.sh first)
set -euo pipefail
NAMESPACE="gravitee-apim"
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
echo "==> Checking prerequisites"
command -v kubectl >/dev/null || { echo "kubectl not found"; exit 1; }
command -v helm >/dev/null || { echo "helm not found"; exit 1; }
echo "==> Verifying cluster reachable"
kubectl cluster-info
echo "==> Verifying cert-manager is installed"
kubectl get crd certificates.cert-manager.io >/dev/null 2>&1 || {
echo "ERROR: cert-manager CRDs not found. Install cert-manager first."
exit 1
}
echo "==> Verifying nginx ingress controller is installed"
kubectl get ingressclass nginx >/dev/null 2>&1 || {
echo "WARNING: 'nginx' IngressClass not found. Ensure nginx-ingress is installed."
}
echo "==> Step 1/5 : Create namespace"
kubectl create namespace "${NAMESPACE}" --dry-run=client -o yaml | kubectl apply -f -
echo "==> Step 2/5 : Create credential secrets (idempotent)"
"${SCRIPT_DIR}/create-secrets.sh"
echo "==> Step 3/5 : Apply cert-manager Issuer + Certificates"
kubectl apply -f "${SCRIPT_DIR}/manifests/cert-manager.yaml"
echo "==> Waiting for CA Issuer to be Ready"
kubectl -n "${NAMESPACE}" wait --for=condition=Ready issuer/gravitee-ca-issuer --timeout=120s
echo "==> Waiting for all Certificates to be Ready"
for cert in gravitee-ca console-tls portal-tls api-tls gateway-tls \
mongodb-tls elasticsearch-tls gateway-internal-tls api-internal-tls; do
echo " - waiting for ${cert}"
kubectl -n "${NAMESPACE}" wait --for=condition=Ready "certificate/${cert}" --timeout=180s
done
echo "==> Step 4/5 : Add Helm repos"
helm repo add bitnami https://charts.bitnami.com/bitnami
helm repo add elastic https://helm.elastic.co
helm repo add graviteeio https://helm.gravitee.io
helm repo update
echo "==> Installing MongoDB"
helm upgrade --install mongodb bitnami/mongodb \
--namespace "${NAMESPACE}" \
--values "${SCRIPT_DIR}/values-mongodb.yaml" \
--wait --timeout 10m
echo "==> Installing Elasticsearch"
helm upgrade --install elasticsearch elastic/elasticsearch \
--namespace "${NAMESPACE}" \
--values "${SCRIPT_DIR}/values-elasticsearch.yaml" \
--wait --timeout 10m
echo "==> Step 5/5 : Installing Gravitee APIM"
helm upgrade --install graviteeio-apim graviteeio/apim \
--namespace "${NAMESPACE}" \
--values "${SCRIPT_DIR}/values-apim.yaml" \
--wait --timeout 15m
echo ""
echo "==> Deployment complete"
echo ""
kubectl get pods -n "${NAMESPACE}"
echo ""
echo "Add to /etc/hosts (replace <NODE_IP>):"
echo " <NODE_IP> gateway.gravitee.sttlab.pc console.gravitee.sttlab.pc portal.gravitee.sttlab.pc api.gravitee.sttlab.pc"
echo ""
echo "URLs (HTTPS, self-signed CA - trust gravitee-ca-tls/ca.crt in your browser):"
echo " - Console : https://console.gravitee.sttlab.pc"
echo " - Portal : https://portal.gravitee.sttlab.pc"
echo " - API : https://api.gravitee.sttlab.pc/management"
echo " - Gateway : https://gateway.gravitee.sttlab.pc"
echo ""
echo "To export the CA cert for your trust store:"
echo " kubectl -n ${NAMESPACE} get secret gravitee-ca-tls -o jsonpath='{.data.ca\\.crt}' | base64 -d > gravitee-ca.crt"
+65
View File
@@ -0,0 +1,65 @@
# Elasticsearch - single node with TLS on HTTP
clusterName: "gravitee-es"
nodeGroup: "master"
replicas: 1
minimumMasterNodes: 1
# Mount the cert-manager-issued cert
secretMounts:
- name: elasticsearch-tls
secretName: elasticsearch-tls
path: /usr/share/elasticsearch/config/tls
defaultMode: "0755"
esConfig:
elasticsearch.yml: |
cluster.name: gravitee-es
network.host: 0.0.0.0
xpack.security.enabled: true
xpack.security.http.ssl.enabled: true
xpack.security.http.ssl.certificate: /usr/share/elasticsearch/config/tls/tls.crt
xpack.security.http.ssl.key: /usr/share/elasticsearch/config/tls/tls.key
xpack.security.http.ssl.certificate_authorities: /usr/share/elasticsearch/config/tls/ca.crt
xpack.security.transport.ssl.enabled: true
xpack.security.transport.ssl.verification_mode: certificate
xpack.security.transport.ssl.certificate: /usr/share/elasticsearch/config/tls/tls.crt
xpack.security.transport.ssl.key: /usr/share/elasticsearch/config/tls/tls.key
xpack.security.transport.ssl.certificate_authorities: /usr/share/elasticsearch/config/tls/ca.crt
# Tell the chart that HTTPS is in use for readiness probes
protocol: https
# Disable cert verification on probes (self-signed)
readinessProbe:
exec:
command:
- bash
- -c
- |
curl -k -s --fail -u "elastic:${ELASTIC_PASSWORD}" https://127.0.0.1:9200/_cluster/health?local=true
esJavaOpts: "-Xms512m -Xmx512m"
resources:
requests:
cpu: 200m
memory: 1Gi
limits:
cpu: 1000m
memory: 2Gi
volumeClaimTemplate:
accessModes: ["ReadWriteOnce"]
storageClassName: local-path
resources:
requests:
storage: 10Gi
createCert: false
sysctlInitContainer:
enabled: false
service:
type: ClusterIP
+41
View File
@@ -0,0 +1,41 @@
# MongoDB - standalone with TLS, credentials sourced from existing secret
architecture: standalone
auth:
enabled: true
rootUser: root
usernames:
- gravitee
databases:
- gravitee
# Reference pre-created secret instead of inline passwords
existingSecret: mongodb-credentials
# Enable TLS on MongoDB server
tls:
enabled: true
autoGenerated: false
mTLS:
enabled: true
standalone:
existingSecret: mongodb-tls
extraFlags:
- "--tlsAllowConnectionsWithoutCertificates"
persistence:
enabled: true
size: 8Gi
storageClass: local-path
resources:
requests:
cpu: 200m
memory: 512Mi
limits:
cpu: 1000m
memory: 1Gi
service:
type: ClusterIP
+57
View File
@@ -0,0 +1,57 @@
#!/usr/bin/env bash
# Create all credential secrets manually before helm install.
# Run once. Re-running with new values requires `kubectl delete secret` first.
set -euo pipefail
NS="gravitee-apim"
MONGO_ROOT_PASSWORD=$(openssl rand -base64 24 | tr -dc 'A-Za-z0-9' | head -c 16)
MONGO_GRAVITEE_PASSWORD=$(openssl rand -base64 24 | tr -dc 'A-Za-z0-9' | head -c 16)
GRAVITEE_ADMIN_PASSWORD=$(openssl rand -base64 24 | tr -dc 'A-Za-z0-9' | head -c 16)
# Ensure namespace exists
kubectl create namespace "${NS}" --dry-run=client -o yaml | kubectl apply -f -
echo "==> Creating MongoDB credentials"
# Used by both the MongoDB chart and the Gravitee chart (consumer)
kubectl -n "${NS}" create secret generic mongodb-credentials \
--from-literal=mongodb-root-password=${MONGO_ROOT_PASSWORD} \
--from-literal=mongodb-passwords=${MONGO_GRAVITEE_PASSWORD} \
--from-literal=mongodb-replica-set-key='' \
--dry-run=client -o yaml | kubectl apply -f -
# Full MongoDB URIs injected via env var override into Gravitee components.
# GRAVITEE_MANAGEMENT_MONGODB_URI overrides management.mongodb.uri in api.
# GRAVITEE_RATELIMIT_MONGODB_URI overrides ratelimit.mongodb.uri in gateway.
MONGO_URI="mongodb://gravitee:${MONGO_GRAVITEE_PASSWORD}@mongodb.gravitee-apim.svc.cluster.local:27017/gravitee?tls=true&authSource=gravitee"
kubectl -n "${NS}" create secret generic gravitee-mongodb-uri \
--from-literal=GRAVITEE_MANAGEMENT_MONGODB_URI="${MONGO_URI}" \
--from-literal=GRAVITEE_RATELIMIT_MONGODB_URI="${MONGO_URI}" \
--dry-run=client -o yaml | kubectl apply -f -
echo "==> Creating Gravitee admin credentials"
ADMIN_BCRYPT=$(htpasswd -bnBC 10 "" "${GRAVITEE_ADMIN_PASSWORD}" | tr -d ':\n')
kubectl -n "${NS}" create secret generic gravitee-admin \
--from-literal=admin-username='admin' \
--from-literal=admin-password-plain="${GRAVITEE_ADMIN_PASSWORD}" \
--from-literal=admin-password-bcrypt="${ADMIN_BCRYPT}" \
--dry-run=client -o yaml | kubectl apply -f -
echo "==> Creating JKS keystore password (used by cert-manager keystores and JAVA_OPTS)"
JKS_PASSWORD=$(openssl rand -base64 24 | tr -dc 'A-Za-z0-9' | head -c 20)
kubectl -n "${NS}" create secret generic gravitee-jks-password \
--from-literal=password="${JKS_PASSWORD}" \
--dry-run=client -o yaml | kubectl apply -f -
echo "==> Creating JWT signing secret (used by Management API)"
JWT_SECRET=$(openssl rand -base64 48 | tr -d '\n')
kubectl -n "${NS}" create secret generic gravitee-jwt \
--from-literal=GRAVITEE_JWT_SECRET="${JWT_SECRET}" \
--dry-run=client -o yaml | kubectl apply -f -
echo ""
echo "==> Done. Secrets created in namespace ${NS}:"
kubectl -n "${NS}" get secrets | grep -E 'mongodb-credentials|gravitee-mongodb-uri|gravitee-admin|gravitee-jwt'
echo ""