1
.gitignore
vendored
1
.gitignore
vendored
@@ -12,3 +12,4 @@ sbom-docker.json
|
||||
*.pem
|
||||
*.crt
|
||||
*.key
|
||||
compose/keycloak/probo-realm.json
|
||||
|
||||
42
GNUmakefile
42
GNUmakefile
@@ -1,13 +1,17 @@
|
||||
NPM?= npm
|
||||
NPX?= npx
|
||||
PRETTIER?= $(NPX) prettier
|
||||
GO?= go
|
||||
DOCKER?= docker
|
||||
SYFT ?= syft
|
||||
GRYPE ?= grype
|
||||
CP ?= cp
|
||||
MKDIR ?= mkdir -p
|
||||
MKCERT ?= mkcert
|
||||
CAT ?= cat
|
||||
CP ?= cp
|
||||
DOCKER ?= docker
|
||||
GO ?= go
|
||||
GRYPE ?= grype
|
||||
MKCERT ?= mkcert
|
||||
MKDIR ?= mkdir -p
|
||||
NPM ?= npm
|
||||
NPX ?= npx
|
||||
OPENSSL ?= openssl
|
||||
PRETTIER ?= $(NPX) prettier
|
||||
SED ?= sed
|
||||
SYFT ?= syft
|
||||
TAIL ?= tail
|
||||
|
||||
DOCKER_BUILD_FLAGS?=
|
||||
DOCKER_BUILD= DOCKER_BUILDKIT=1 $(DOCKER) build $(DOCKER_BUILD_FLAGS)
|
||||
@@ -95,8 +99,8 @@ test-e2e-coverage: bin/probod-coverage ## Run e2e tests with coverage
|
||||
|
||||
.PHONY: coverage-combined
|
||||
coverage-combined: coverage-report test-e2e-coverage ## Generate combined coverage report (unit + e2e)
|
||||
@cat coverage.out > coverage-combined.out
|
||||
@tail -n +2 coverage-e2e.out >> coverage-combined.out
|
||||
@$(CAT) coverage.out > coverage-combined.out
|
||||
@$(TAIL) -n +2 coverage-e2e.out >> coverage-combined.out
|
||||
$(GO) tool cover -html=coverage-combined.out -o=coverage-combined.html
|
||||
|
||||
.PHONY: build
|
||||
@@ -206,7 +210,7 @@ clean: ## Clean the project (node_modules and build artifacts)
|
||||
$(RM) -rf coverage/
|
||||
|
||||
.PHONY: stack-up
|
||||
stack-up: compose/pebble/certs/rootCA.pem ## Start the docker stack as a deamon
|
||||
stack-up: compose/pebble/certs/rootCA.pem compose/keycloak/probo-realm.json ## Start the docker stack as a deamon
|
||||
$(DOCKER_COMPOSE) up -d
|
||||
|
||||
.PHONY: stack-down
|
||||
@@ -230,9 +234,19 @@ goreleaser-check: ## Check goreleaser configuration
|
||||
goreleaser check
|
||||
|
||||
compose/pebble/certs/rootCA.pem:
|
||||
@$(MKDIR) -p compose/pebble/certs
|
||||
@$(MKDIR) compose/pebble/certs
|
||||
$(MKCERT) -cert-file compose/pebble/certs/pebble.crt \
|
||||
-key-file compose/pebble/certs/pebble.key \
|
||||
localhost 127.0.0.1 ::1 pebble
|
||||
$(CP) "$$($(MKCERT) -CAROOT)/rootCA.pem" compose/pebble/certs/rootCA.pem
|
||||
$(CP) "$$($(MKCERT) -CAROOT)/rootCA-key.pem" compose/pebble/certs/rootCA-key.pem
|
||||
|
||||
compose/keycloak/certs/cert.pem:
|
||||
$(MKDIR) ./compose/keycloak/certs
|
||||
$(OPENSSL) req -x509 -newkey rsa:2048 -keyout compose/keycloak/certs/private-key.pem -out compose/keycloak/certs/cert.pem -days 3650 -nodes -subj "/CN=keycloak-saml-signing"
|
||||
|
||||
compose/keycloak/probo-realm.json: compose/keycloak/probo-realm.json.tmpl compose/keycloak/certs/cert.pem
|
||||
$(SED) \
|
||||
-e "s|CERTIFICATE_PLACEHOLDER|$$(awk 'NR==1 {printf "%s", $$0; next} {printf "\\\\n%s", $$0}' compose/keycloak/certs/cert.pem)|g" \
|
||||
-e "s|PRIVATE_KEY_PLACEHOLDER|$$(awk 'NR==1 {printf "%s", $$0; next} {printf "\\\\n%s", $$0}' compose/keycloak/certs/private-key.pem)|g" \
|
||||
$@.tmpl > $@
|
||||
|
||||
29
compose.yaml
29
compose.yaml
@@ -19,7 +19,7 @@ services:
|
||||
interval: 5s
|
||||
timeout: 5s
|
||||
retries: 5
|
||||
|
||||
|
||||
minio:
|
||||
image: "quay.io/minio/minio"
|
||||
entrypoint: "sh"
|
||||
@@ -33,7 +33,7 @@ services:
|
||||
environment:
|
||||
MINIO_ROOT_USER: "probod"
|
||||
MINIO_ROOT_PASSWORD: "thisisnotasecret"
|
||||
|
||||
|
||||
grafana:
|
||||
image: "grafana/grafana:latest"
|
||||
ports:
|
||||
@@ -129,9 +129,34 @@ services:
|
||||
- "8056:8056" # Management API
|
||||
command: -dns01 ":8053" -http01 ":8055" -management ":8056"
|
||||
|
||||
keycloak:
|
||||
image: quay.io/keycloak/keycloak:latest
|
||||
user: root
|
||||
environment:
|
||||
KC_HOSTNAME: localhost
|
||||
KC_HOSTNAME_PORT: 8082
|
||||
KC_HOSTNAME_STRICT: false
|
||||
KC_HOSTNAME_STRICT_HTTPS: false
|
||||
|
||||
KC_LOG_LEVEL: info
|
||||
KC_METRICS_ENABLED: true
|
||||
KC_HEALTH_ENABLED: true
|
||||
KEYCLOAK_ADMIN: admin
|
||||
KEYCLOAK_ADMIN_PASSWORD: admin
|
||||
command:
|
||||
- "start-dev"
|
||||
- "--import-realm"
|
||||
- "--verbose"
|
||||
ports:
|
||||
- 8082:8080
|
||||
volumes:
|
||||
- "./compose/keycloak:/opt/keycloak/data/import:ro"
|
||||
- "keycloak-data:/opt/keycloak/data/h2:rw"
|
||||
|
||||
volumes:
|
||||
postgres-data:
|
||||
minio-data:
|
||||
grafana-data:
|
||||
prometheus-data:
|
||||
tempo-data:
|
||||
keycloak-data:
|
||||
|
||||
194
compose/keycloak/probo-realm.json.tmpl
Normal file
194
compose/keycloak/probo-realm.json.tmpl
Normal file
@@ -0,0 +1,194 @@
|
||||
{
|
||||
"id": "probo",
|
||||
"realm": "probo",
|
||||
"displayName": "Probo",
|
||||
"enabled": true,
|
||||
"sslRequired": "none",
|
||||
"registrationAllowed": false,
|
||||
"loginWithEmailAllowed": true,
|
||||
"duplicateEmailsAllowed": false,
|
||||
"resetPasswordAllowed": true,
|
||||
"editUsernameAllowed": false,
|
||||
"bruteForceProtected": true,
|
||||
"roles": {
|
||||
"realm": [
|
||||
{
|
||||
"name": "admin",
|
||||
"description": "Administrator role"
|
||||
},
|
||||
{
|
||||
"name": "member",
|
||||
"description": "Regular member role"
|
||||
},
|
||||
{
|
||||
"name": "viewer",
|
||||
"description": "Read-only viewer role"
|
||||
}
|
||||
]
|
||||
},
|
||||
"defaultRoles": ["member"],
|
||||
"clients": [
|
||||
{
|
||||
"clientId": "http://localhost:5173/connect/saml/metadata",
|
||||
"name": "Probo Console",
|
||||
"description": "Probo GRC Platform - SAML Service Provider",
|
||||
"enabled": true,
|
||||
"protocol": "saml",
|
||||
"fullScopeAllowed": true,
|
||||
"frontchannelLogout": true,
|
||||
"attributes": {
|
||||
"saml.assertion.signature": "true",
|
||||
"saml.force.post.binding": "true",
|
||||
"saml.multivalued.roles": "false",
|
||||
"saml.encrypt": "false",
|
||||
"saml.server.signature": "true",
|
||||
"saml.server.signature.keyinfo.ext": "false",
|
||||
"saml.signature.algorithm": "RSA_SHA256",
|
||||
"saml_force_name_id_format": "true",
|
||||
"saml_name_id_format": "email",
|
||||
"saml.client.signature": "false",
|
||||
"saml.authnstatement": "true",
|
||||
"saml_single_logout_service_url_post": "http://localhost:5173/connect/saml/logout",
|
||||
"saml_single_logout_service_url_redirect": "http://localhost:5173/connect/saml/logout",
|
||||
"saml.onetimeuse.condition": "false"
|
||||
},
|
||||
"rootUrl": "http://localhost:5173",
|
||||
"baseUrl": "/",
|
||||
"adminUrl": "http://localhost:5173/connect/saml/consume",
|
||||
"redirectUris": ["http://localhost:5173/*"],
|
||||
"webOrigins": ["http://localhost:5173"],
|
||||
"protocolMappers": [
|
||||
{
|
||||
"name": "email",
|
||||
"protocol": "saml",
|
||||
"protocolMapper": "saml-user-property-mapper",
|
||||
"consentRequired": false,
|
||||
"config": {
|
||||
"attribute.nameformat": "Basic",
|
||||
"user.attribute": "email",
|
||||
"friendly.name": "email",
|
||||
"attribute.name": "email"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "firstName",
|
||||
"protocol": "saml",
|
||||
"protocolMapper": "saml-user-property-mapper",
|
||||
"consentRequired": false,
|
||||
"config": {
|
||||
"attribute.nameformat": "Basic",
|
||||
"user.attribute": "firstName",
|
||||
"friendly.name": "firstName",
|
||||
"attribute.name": "firstName"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "lastName",
|
||||
"protocol": "saml",
|
||||
"protocolMapper": "saml-user-property-mapper",
|
||||
"consentRequired": false,
|
||||
"config": {
|
||||
"attribute.nameformat": "Basic",
|
||||
"user.attribute": "lastName",
|
||||
"friendly.name": "lastName",
|
||||
"attribute.name": "lastName"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "role",
|
||||
"protocol": "saml",
|
||||
"protocolMapper": "saml-role-list-mapper",
|
||||
"consentRequired": false,
|
||||
"config": {
|
||||
"single": "true",
|
||||
"attribute.nameformat": "Basic",
|
||||
"friendly.name": "role",
|
||||
"attribute.name": "role"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"components": {
|
||||
"org.keycloak.keys.KeyProvider": [
|
||||
{
|
||||
"name": "custom-saml-signing",
|
||||
"providerId": "rsa",
|
||||
"config": {
|
||||
"priority": ["200"],
|
||||
"enabled": ["true"],
|
||||
"active": ["true"],
|
||||
|
||||
"certificate": ["CERTIFICATE_PLACEHOLDER"],
|
||||
"privateKey": ["PRIVATE_KEY_PLACEHOLDER"]
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
"users": [
|
||||
{
|
||||
"username": "owner@example.com",
|
||||
"email": "owner@example.com",
|
||||
"emailVerified": true,
|
||||
"enabled": true,
|
||||
"firstName": "Owner",
|
||||
"lastName": "User",
|
||||
"credentials": [
|
||||
{
|
||||
"type": "password",
|
||||
"value": "owner@example.com",
|
||||
"temporary": false
|
||||
}
|
||||
],
|
||||
"realmRoles": ["owner"]
|
||||
},
|
||||
{
|
||||
"username": "admin@example.com",
|
||||
"email": "admin@example.com",
|
||||
"emailVerified": true,
|
||||
"enabled": true,
|
||||
"firstName": "Admin",
|
||||
"lastName": "User",
|
||||
"credentials": [
|
||||
{
|
||||
"type": "password",
|
||||
"value": "admin@example.com",
|
||||
"temporary": false
|
||||
}
|
||||
],
|
||||
"realmRoles": ["admin"]
|
||||
},
|
||||
{
|
||||
"username": "member@example.com",
|
||||
"email": "member@example.com",
|
||||
"emailVerified": true,
|
||||
"enabled": true,
|
||||
"firstName": "Member",
|
||||
"lastName": "User",
|
||||
"credentials": [
|
||||
{
|
||||
"type": "password",
|
||||
"value": "member123",
|
||||
"temporary": false
|
||||
}
|
||||
],
|
||||
"realmRoles": ["member"]
|
||||
},
|
||||
{
|
||||
"username": "viewer@example.com",
|
||||
"email": "viewer@example.com",
|
||||
"emailVerified": true,
|
||||
"enabled": true,
|
||||
"firstName": "Viewer",
|
||||
"lastName": "User",
|
||||
"credentials": [
|
||||
{
|
||||
"type": "password",
|
||||
"value": "viewer@example.com",
|
||||
"temporary": false
|
||||
}
|
||||
],
|
||||
"realmRoles": ["viewer"]
|
||||
}
|
||||
]
|
||||
}
|
||||
Reference in New Issue
Block a user