stuff
This commit is contained in:
35
database/main.yml
Normal file
35
database/main.yml
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
---
|
||||||
|
apiVersion: stackgres.io/v1
|
||||||
|
kind: SGPostgresConfig
|
||||||
|
metadata:
|
||||||
|
name: database
|
||||||
|
namespace: mainscnt
|
||||||
|
spec:
|
||||||
|
postgresVersion: '15'
|
||||||
|
postgresql.conf:
|
||||||
|
shared_preload_libraries: timescaledb
|
||||||
|
max_worker_processes: '32'
|
||||||
|
max_parallel_workers: '16'
|
||||||
|
---
|
||||||
|
apiVersion: stackgres.io/v1
|
||||||
|
kind: SGCluster
|
||||||
|
metadata:
|
||||||
|
name: database
|
||||||
|
namespace: mainscnt
|
||||||
|
spec:
|
||||||
|
instances: 1
|
||||||
|
postgres:
|
||||||
|
version: '15'
|
||||||
|
extensions:
|
||||||
|
- name: timescaledb
|
||||||
|
ssl:
|
||||||
|
enabled: true
|
||||||
|
configurations:
|
||||||
|
sgPostgresConfig: database
|
||||||
|
pods:
|
||||||
|
persistentVolume:
|
||||||
|
size: '1000Gi'
|
||||||
|
storageClass: nfs-client
|
||||||
|
disableConnectionPooling: true
|
||||||
|
|
||||||
|
|
8
database/restart.yml
Normal file
8
database/restart.yml
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
apiVersion: stackgres.io/v1
|
||||||
|
kind: SGDbOps
|
||||||
|
metadata:
|
||||||
|
name: restart-002
|
||||||
|
spec:
|
||||||
|
sgCluster: database
|
||||||
|
op: restart
|
||||||
|
|
48
database/setup-database.sh
Executable file
48
database/setup-database.sh
Executable file
@ -0,0 +1,48 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
|
||||||
|
DATABASE=mainscnt
|
||||||
|
LOGIN=sink
|
||||||
|
PASSWORD=`openssl rand -base64 24`
|
||||||
|
SUPERUSER_LOGIN=$(kubectl get secret -n mainscnt database -o jsonpath="{.data.superuser-username}" | base64 --decode)
|
||||||
|
SUPERUSER_PASSWORD=$(kubectl get secret -n mainscnt database -o jsonpath="{.data.superuser-password}" | base64 --decode)
|
||||||
|
|
||||||
|
|
||||||
|
kubectl run psql \
|
||||||
|
--stdin=true \
|
||||||
|
--tty=true \
|
||||||
|
--rm=true \
|
||||||
|
--image=postgres:15-alpine \
|
||||||
|
-n $NAMESPACE \
|
||||||
|
--restart=Never \
|
||||||
|
--env="PGPASSWORD=$SUPERUSER_PASSWORD" \
|
||||||
|
--env="PGUSER=$SUPERUSER_LOGIN" \
|
||||||
|
-- \
|
||||||
|
psql -h database.mainscnt.svc.cluster.local <<EOF
|
||||||
|
do
|
||||||
|
\$\$
|
||||||
|
begin
|
||||||
|
if not exists (SELECT * FROM pg_database WHERE datname = '$DATABASE') then
|
||||||
|
CREATE DATABASE $DATABASE;
|
||||||
|
end if;
|
||||||
|
if not exists (SELECT * FROM pg_user WHERE usename = '$LOGIN') then
|
||||||
|
CREATE USER $LOGIN WITH PASSWORD '$PASSWORD';
|
||||||
|
else
|
||||||
|
ALTER USER $LOGIN WITH PASSWORD '$PASSWORD';
|
||||||
|
end if;
|
||||||
|
GRANT ALL PRIVILEGES ON DATABASE $DATABASE TO $LOGIN;
|
||||||
|
end
|
||||||
|
\$\$
|
||||||
|
;
|
||||||
|
commit;
|
||||||
|
EOF
|
||||||
|
|
||||||
|
kubectl create secret generic sinkserver-secret \
|
||||||
|
--dry-run=client \
|
||||||
|
-o yaml \
|
||||||
|
--save-config \
|
||||||
|
--from-literal=dbpass="$PASSWORD" | \
|
||||||
|
kubectl apply -f - -n $NAMESPACE
|
||||||
|
|
||||||
|
|
||||||
|
|
22
grafana/ingress.yml
Normal file
22
grafana/ingress.yml
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
apiVersion: networking.k8s.io/v1
|
||||||
|
kind: Ingress
|
||||||
|
metadata:
|
||||||
|
name: grafana
|
||||||
|
annotations:
|
||||||
|
cert-manager.io/cluster-issuer: letsencrypt-production-http
|
||||||
|
spec:
|
||||||
|
tls:
|
||||||
|
- hosts:
|
||||||
|
- grafana.mainscnt.eu
|
||||||
|
secretName: grafana-cert
|
||||||
|
rules:
|
||||||
|
- host: grafana.mainscnt.eu
|
||||||
|
http:
|
||||||
|
paths:
|
||||||
|
- path: /
|
||||||
|
pathType: Prefix
|
||||||
|
backend:
|
||||||
|
service:
|
||||||
|
name: mainscntgrafana
|
||||||
|
port:
|
||||||
|
number: 80
|
28
grafana/install.sh
Executable file
28
grafana/install.sh
Executable file
@ -0,0 +1,28 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
ARG1=$1
|
||||||
|
NAMESPACE=$(cat namespace)
|
||||||
|
|
||||||
|
echo "Namespace: $NAMESPACE"
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
if [ "$ARG1" = "initial" ]; then
|
||||||
|
psql << EOF
|
||||||
|
create user mainscntgrafana;
|
||||||
|
commit;
|
||||||
|
create database mainscntgrafana with owner mainscntgrafana;
|
||||||
|
EOF
|
||||||
|
fi
|
||||||
|
|
||||||
|
./roll-db-credential.sh
|
||||||
|
|
||||||
|
helm repo add grafana https://grafana.github.io/helm-charts
|
||||||
|
helm repo update
|
||||||
|
helm upgrade --install -f values.yml mainscntgrafana grafana/grafana --version 6.59.0 --namespace=$NAMESPACE
|
||||||
|
|
||||||
|
kubectl annotate deployments mainscntgrafana -n $NAMESPACE --overwrite=true secret.reloader.stakater.com/reload=grafana-db-cred
|
||||||
|
|
||||||
|
kubectl -f ingress.yml -n $NAMESPACE apply
|
||||||
|
|
1
grafana/namespace
Normal file
1
grafana/namespace
Normal file
@ -0,0 +1 @@
|
|||||||
|
mainscnt
|
108
grafana/provisioning.json
Normal file
108
grafana/provisioning.json
Normal file
@ -0,0 +1,108 @@
|
|||||||
|
[
|
||||||
|
{
|
||||||
|
"name": "createClientMainscntGrafana",
|
||||||
|
"method": "POST",
|
||||||
|
"url": "https://auth2.hottis.de/admin/realms/hottis/clients",
|
||||||
|
"data": {
|
||||||
|
"protocol": "openid-connect",
|
||||||
|
"enabled": "true",
|
||||||
|
"clientId": "mainscnt-grafana",
|
||||||
|
"name": "Grafana2",
|
||||||
|
"baseUrl": "https://grafana.mainscnt.eu",
|
||||||
|
"redirectUris": [
|
||||||
|
"https://grafana.mainscnt.eu/login/generic_oauth"
|
||||||
|
],
|
||||||
|
"standardFlowEnabled": "true",
|
||||||
|
"implicitFlowEnabled": "false",
|
||||||
|
"publicClient": "false"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "createClientRoleMaincntGrafanaAdmin",
|
||||||
|
"method": "POST",
|
||||||
|
"url": "https://auth2.hottis.de/admin/realms/hottis/clients/$result/roles",
|
||||||
|
"use": {
|
||||||
|
"url": "https://auth2.hottis.de/admin/realms/hottis/clients",
|
||||||
|
"data": { "clientId": "mainscnt-grafana" },
|
||||||
|
"resultIndexes": [ 0, "id" ]
|
||||||
|
},
|
||||||
|
"data": {
|
||||||
|
"name": "Admin"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "createClientRoleMainscntGrafanaGrafanaAdmin",
|
||||||
|
"method": "POST",
|
||||||
|
"url": "https://auth2.hottis.de/admin/realms/hottis/clients/$result/roles",
|
||||||
|
"use": {
|
||||||
|
"url": "https://auth2.hottis.de/admin/realms/hottis/clients",
|
||||||
|
"data": { "clientId": "mainscnt-grafana" },
|
||||||
|
"resultIndexes": [ 0, "id" ]
|
||||||
|
},
|
||||||
|
"data": {
|
||||||
|
"name": "GrafanaAdmin"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "createClientRoleMainscntGrafanaViewer",
|
||||||
|
"method": "POST",
|
||||||
|
"url": "https://auth2.hottis.de/admin/realms/hottis/clients/$result/roles",
|
||||||
|
"use": {
|
||||||
|
"url": "https://auth2.hottis.de/admin/realms/hottis/clients",
|
||||||
|
"data": { "clientId": "mainscnt-grafana" },
|
||||||
|
"resultIndexes": [ 0, "id" ]
|
||||||
|
},
|
||||||
|
"data": {
|
||||||
|
"name": "Viewer"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "createClientRoleMainscntGrafanaEditor",
|
||||||
|
"method": "POST",
|
||||||
|
"url": "https://auth2.hottis.de/admin/realms/hottis/clients/$result/roles",
|
||||||
|
"use": {
|
||||||
|
"url": "https://auth2.hottis.de/admin/realms/hottis/clients",
|
||||||
|
"data": { "clientId": "mainscnt-grafana" },
|
||||||
|
"resultIndexes": [ 0, "id" ]
|
||||||
|
},
|
||||||
|
"data": {
|
||||||
|
"name": "Editor"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "createRoleMapperMainscntGrafana",
|
||||||
|
"method": "POST",
|
||||||
|
"url": "https://auth2.hottis.de/admin/realms/hottis/clients/$result/protocol-mappers/add-models",
|
||||||
|
"use": {
|
||||||
|
"url": "https://auth2.hottis.de/admin/realms/hottis/clients",
|
||||||
|
"data": { "clientId": "mainscnt-grafana" },
|
||||||
|
"resultIndexes": [ 0, "id" ]
|
||||||
|
},
|
||||||
|
"data": [
|
||||||
|
{
|
||||||
|
"name": "client roles",
|
||||||
|
"protocol": "openid-connect",
|
||||||
|
"protocolMapper": "oidc-usermodel-client-role-mapper",
|
||||||
|
"consentRequired": false,
|
||||||
|
"config": {
|
||||||
|
"multivalued": "true",
|
||||||
|
"user.attribute": "foo",
|
||||||
|
"access.token.claim": "true",
|
||||||
|
"claim.name": "roles",
|
||||||
|
"jsonType.label": "String",
|
||||||
|
"id.token.claim": "true",
|
||||||
|
"access.token.claim": "true",
|
||||||
|
"clientId": "mainscnt-grafana"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "getClientMainscntGrafana",
|
||||||
|
"method": "GET",
|
||||||
|
"url": "https://auth2.hottis.de/admin/realms/hottis/clients",
|
||||||
|
"data": { "clientId": "mainscnt-grafana" }
|
||||||
|
}
|
||||||
|
]
|
||||||
|
|
||||||
|
|
5
grafana/readme.md
Normal file
5
grafana/readme.md
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
For the OAuth configuration follow the docs at
|
||||||
|
https://grafana.com/docs/grafana/latest/setup-grafana/configure-security/configure-authentication/generic-oauth/
|
||||||
|
|
||||||
|
With keycloak create under "client scopes" a dedicated mapper to fill the client roles into the claim roles.
|
||||||
|
|
33
grafana/roll-db-credential.sh
Executable file
33
grafana/roll-db-credential.sh
Executable file
@ -0,0 +1,33 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
|
||||||
|
DATABASE=mainscntgrafana
|
||||||
|
LOGIN=mainscntgrafana
|
||||||
|
PASSWORD=`openssl rand -base64 24`
|
||||||
|
NAMESPACE=$(cat namespace)
|
||||||
|
|
||||||
|
psql <<EOF
|
||||||
|
do
|
||||||
|
\$\$
|
||||||
|
begin
|
||||||
|
if not exists (SELECT * FROM pg_user WHERE usename = '$LOGIN') then
|
||||||
|
CREATE USER $LOGIN WITH PASSWORD '$PASSWORD';
|
||||||
|
else
|
||||||
|
ALTER USER $LOGIN WITH PASSWORD '$PASSWORD';
|
||||||
|
end if;
|
||||||
|
GRANT ALL PRIVILEGES ON DATABASE $DATABASE TO $LOGIN;
|
||||||
|
end
|
||||||
|
\$\$
|
||||||
|
;
|
||||||
|
commit;
|
||||||
|
EOF
|
||||||
|
|
||||||
|
kubectl create secret generic grafana-db-cred \
|
||||||
|
--dry-run=client \
|
||||||
|
-o yaml \
|
||||||
|
--save-config \
|
||||||
|
--from-literal=GF_DATABASE_USER="$LOGIN" \
|
||||||
|
--from-literal=GF_DATABASE_PASSWORD="$PASSWORD" | \
|
||||||
|
kubectl apply -f - -n $NAMESPACE
|
||||||
|
|
||||||
|
|
22
grafana/test.yml
Normal file
22
grafana/test.yml
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
apiVersion: v1
|
||||||
|
kind: Pod
|
||||||
|
metadata:
|
||||||
|
name: secretloader
|
||||||
|
labels:
|
||||||
|
app: secretloader
|
||||||
|
spec:
|
||||||
|
containers:
|
||||||
|
- name: secretloader
|
||||||
|
image: nginx
|
||||||
|
env:
|
||||||
|
- name: USERNAME
|
||||||
|
valueFrom:
|
||||||
|
secretKeyRef:
|
||||||
|
name: grafana-admin-credentials
|
||||||
|
key: username
|
||||||
|
- name: PASSWORD
|
||||||
|
valueFrom:
|
||||||
|
secretKeyRef:
|
||||||
|
name: grafana-admin-credentials
|
||||||
|
key: password
|
||||||
|
|
51
grafana/values.yml
Normal file
51
grafana/values.yml
Normal file
@ -0,0 +1,51 @@
|
|||||||
|
persistence:
|
||||||
|
enabled: true
|
||||||
|
storageClassName: nfs-client
|
||||||
|
|
||||||
|
grafana.ini:
|
||||||
|
server:
|
||||||
|
root_url: https://grafana.mainscnt.eu
|
||||||
|
smtp:
|
||||||
|
enabled: true
|
||||||
|
host: smtp.system.svc.cluster.local
|
||||||
|
from_address: grafana@mainscnt.eu
|
||||||
|
from_name: "Mainscnt Grafana Pseudouser"
|
||||||
|
log:
|
||||||
|
level: debug
|
||||||
|
emails:
|
||||||
|
welcome_email_on_sign_up: true
|
||||||
|
security:
|
||||||
|
cookie_secure: true
|
||||||
|
cookie_samesite: none
|
||||||
|
auth:
|
||||||
|
disable_login_form: true
|
||||||
|
auth.generic_oauth:
|
||||||
|
enabled: true
|
||||||
|
name: Mainscnt Grafana via Keycloak
|
||||||
|
allow_sign_up: true
|
||||||
|
client_id: mainscnt-grafana
|
||||||
|
client_secret: ...
|
||||||
|
scopes: openid email profile offline_access roles
|
||||||
|
email_attribute_path: email
|
||||||
|
login_attribute_path: username
|
||||||
|
name_attribute_path: fullname
|
||||||
|
auth_url: https://auth2.hottis.de/realms/hottis/protocol/openid-connect/auth
|
||||||
|
token_url: https://auth2.hottis.de/realms/hottis/protocol/openid-connect/token
|
||||||
|
api_url: https://auth2.hottis.de/realms/hottis/protocol/openid-connect/userinfo
|
||||||
|
role_attribute_path: "contains(roles[*], 'GrafanaAdmin') && 'GrafanaAdmin' || contains(roles[*], 'Admin') && 'Admin' || contains(roles[*], 'Editor') && 'Editor' || contains(roles[*], 'Viewer') && 'Viewer'"
|
||||||
|
role_attribute_strict: true
|
||||||
|
allow_assign_grafana_admin: true
|
||||||
|
tls_skip_verify_insecure: true
|
||||||
|
database:
|
||||||
|
type: postgres
|
||||||
|
host: timescaledb.database.svc.cluster.local
|
||||||
|
name: mainscntgrafana
|
||||||
|
ssl_mode: require
|
||||||
|
|
||||||
|
# add the oauth client secret in this secret with the key GF_AUTH_GENERIC_OAUTH_CLIENT_SECRET
|
||||||
|
# example:
|
||||||
|
# kubectl create secret generic grafana-oauth-secret --from-literal=GF_AUTH_GENERIC_OAUTH_CLIENT_SECRET="geheim"
|
||||||
|
envFromSecrets:
|
||||||
|
- name: grafana-oauth-secret
|
||||||
|
- name: grafana-db-cred
|
||||||
|
|
18
install.sh
Executable file
18
install.sh
Executable file
@ -0,0 +1,18 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
export NAMESPACE=$(cat namespace)
|
||||||
|
|
||||||
|
kubectl create namespace $NAMESPACE --dry-run=client -o yaml | kubectl -f - apply
|
||||||
|
|
||||||
|
kubectl apply -f ./database/main.yml -n $NAMESPACE
|
||||||
|
while true; do
|
||||||
|
kubectl get -n $NAMESPACE pod database-0 && break
|
||||||
|
echo "pod not yet available"
|
||||||
|
sleep 5
|
||||||
|
done
|
||||||
|
echo "waiting for database to get ready"
|
||||||
|
kubectl wait --for=condition=ready -n $NAMESPACE --timeout=600s pod database-0
|
||||||
|
|
||||||
|
./database/setup-database.sh
|
||||||
|
|
||||||
|
|
9
nodered/install.sh
Executable file
9
nodered/install.sh
Executable file
@ -0,0 +1,9 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
if [ "$NAMESPACE" = "" ]; then
|
||||||
|
NAMESPACE=$(cat ../namespace)
|
||||||
|
fi
|
||||||
|
|
||||||
|
helm repo add geek-cookbook https://geek-cookbook.github.io/charts/
|
||||||
|
helm repo update
|
||||||
|
helm upgrade --install -n $NAMESPACE -f values.yml nodered geek-cookbook/node-red --version 10.3.2
|
8
nodered/values.yml
Normal file
8
nodered/values.yml
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
env:
|
||||||
|
NODE_RED_ENABLE_PROJECTS: true
|
||||||
|
persistence:
|
||||||
|
data:
|
||||||
|
enabled: true
|
||||||
|
storageClass: nfs-client
|
||||||
|
accessMode: ReadWriteOnce
|
||||||
|
size: 1Gi
|
@ -1,25 +1,3 @@
|
|||||||
apiVersion: networking.k8s.io/v1
|
|
||||||
kind: NetworkPolicy
|
|
||||||
metadata:
|
|
||||||
namespace: mainscnt
|
|
||||||
name: deny-all-but-dns
|
|
||||||
spec:
|
|
||||||
podSelector:
|
|
||||||
matchLabels: {}
|
|
||||||
policyTypes:
|
|
||||||
- Egress
|
|
||||||
- Ingress
|
|
||||||
egress:
|
|
||||||
- to:
|
|
||||||
- namespaceSelector:
|
|
||||||
matchLabels:
|
|
||||||
kubernetes.io/metadata.name: kube-system
|
|
||||||
ports:
|
|
||||||
- protocol: UDP
|
|
||||||
port: 53
|
|
||||||
- protocol: TCP
|
|
||||||
port: 53
|
|
||||||
---
|
|
||||||
apiVersion: apps/v1
|
apiVersion: apps/v1
|
||||||
kind: Deployment
|
kind: Deployment
|
||||||
metadata:
|
metadata:
|
||||||
@ -28,7 +6,7 @@ metadata:
|
|||||||
labels:
|
labels:
|
||||||
app: sinkserver
|
app: sinkserver
|
||||||
spec:
|
spec:
|
||||||
replicas: 3
|
replicas: 1
|
||||||
selector:
|
selector:
|
||||||
matchLabels:
|
matchLabels:
|
||||||
app: sinkserver
|
app: sinkserver
|
||||||
@ -70,72 +48,3 @@ spec:
|
|||||||
- protocol: UDP
|
- protocol: UDP
|
||||||
port: 20169
|
port: 20169
|
||||||
targetPort: 20169
|
targetPort: 20169
|
||||||
---
|
|
||||||
apiVersion: networking.k8s.io/v1
|
|
||||||
kind: NetworkPolicy
|
|
||||||
metadata:
|
|
||||||
name: allow-database-sinkserver
|
|
||||||
namespace: database
|
|
||||||
spec:
|
|
||||||
podSelector:
|
|
||||||
matchLabels:
|
|
||||||
app: timescaledb
|
|
||||||
policyTypes:
|
|
||||||
- Ingress
|
|
||||||
ingress:
|
|
||||||
- from:
|
|
||||||
- podSelector:
|
|
||||||
matchLabels:
|
|
||||||
app: sinkserver
|
|
||||||
- namespaceSelector:
|
|
||||||
matchLabels:
|
|
||||||
kubernetes.io/metadata.name: mainscnt
|
|
||||||
ports:
|
|
||||||
- protocol: TCP
|
|
||||||
port: 5432
|
|
||||||
---
|
|
||||||
apiVersion: networking.k8s.io/v1
|
|
||||||
kind: NetworkPolicy
|
|
||||||
metadata:
|
|
||||||
name: allow-sinkserver-database
|
|
||||||
namespace: mainscnt
|
|
||||||
spec:
|
|
||||||
podSelector:
|
|
||||||
matchLabels:
|
|
||||||
app: sinkserver
|
|
||||||
policyTypes:
|
|
||||||
- Egress
|
|
||||||
egress:
|
|
||||||
- to:
|
|
||||||
- podSelector:
|
|
||||||
matchLabels:
|
|
||||||
app: timescaledb
|
|
||||||
- namespaceSelector:
|
|
||||||
matchLabels:
|
|
||||||
kubernetes.io/metadata.name: database
|
|
||||||
ports:
|
|
||||||
- protocol: TCP
|
|
||||||
port: 5432
|
|
||||||
---
|
|
||||||
apiVersion: networking.k8s.io/v1
|
|
||||||
kind: NetworkPolicy
|
|
||||||
metadata:
|
|
||||||
name: allow-sinkserver-ingress
|
|
||||||
namespace: mainscnt
|
|
||||||
spec:
|
|
||||||
podSelector:
|
|
||||||
matchLabels:
|
|
||||||
app: sinkserver
|
|
||||||
policyTypes:
|
|
||||||
- Ingress
|
|
||||||
ingress:
|
|
||||||
- from:
|
|
||||||
- ipBlock:
|
|
||||||
cidr: 0.0.0.0/0
|
|
||||||
ports:
|
|
||||||
- protocol: UDP
|
|
||||||
port: 20169
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user