diff --git a/docker-compose/.env.keycloak b/docker-compose/.env.keycloak new file mode 100644 index 0000000..a21feb4 --- /dev/null +++ b/docker-compose/.env.keycloak @@ -0,0 +1,15 @@ +SERVICECONTROL_TAG=latest +SERVICEPULSE_TAG=latest +TRANSPORTTYPE=RabbitMQ.QuorumConventionalRouting +CONNECTIONSTRING="host=rabbitmq;username=guest;password=guest" +PARTICULARSOFTWARE_LICENSE="$PARTICULARSOFTWARE_LICENSE" + +CERTIFICATE_PASSWORD="password" +IDP_AUTHORITY="https://localhost:8282/realms/ServicePulse/" +SERVICECONTROL_AUDIENCE="ServicePulse" +SERVICEPULSE_CLIENTID="ServicePulse" +SERVICEPULSE_APISCOPES=["Pulse"] + + +CERTIFICATE_PATH="./certs/servicecontrol.pfx" +CA_BUNDLE_PATH="./certs/ca-bundle.crt" \ No newline at end of file diff --git a/docker-compose/README.md b/docker-compose/README.md index 362e512..26353ef 100644 --- a/docker-compose/README.md +++ b/docker-compose/README.md @@ -6,13 +6,11 @@ Running ServiceControl and ServicePulse locally in containers provides a way to ## Usage - **Pull the latest images:** Before running the containers, ensure you're using the latest version of each image by executing the following command: +**Pull the latest images:** Before running the containers, ensure you're using the latest version of each image by executing the following command: - ```pwsh - docker compose pull - ``` - -This command checks for any updates to the images specified in the docker-compose.yml file and pulls them if available. +```pwsh +docker compose pull +``` **Start the containers:** After pulling the latest images, modify the [environment file](.env), if necessary, and then start up the containers using: @@ -42,18 +40,14 @@ The `compose-secure.yml` file provides a configuration with HTTPS enabled and OA ### Prerequisites -1. **SSL Certificate**: A PFX certificate file for HTTPS -2. **CA Bundle**: A CA certificate bundle for validating the identity provider's certificates +1. **SSL Certificate**: A PFX certificate file — see [Generating a certificate](#generating-a-certificate-local-testing-only) below +2. **CA Bundle**: A PEM file containing the CA that signed your certificate — see [Generating a CA bundle](#generating-a-ca-bundle-local-testing-only) below 3. **Microsoft Entra ID App Registration**: Configure an app registration for authentication -> [!NOTE] -> The [PFX file](#generate-a-pfx-certificate-for-local-testing-only) contains the private key and certificate for the service to **serve** HTTPS. The [CA bundle](#generate-a-ca-bundle-for-local-testing-only) contains only public CA certificates for the service to **verify** other services' certificates. Both are required when containers communicate over HTTPS. - ### Configuration -Add the following variables to your `.env` file and replace the `{placeholder}` values with your actual configuration: +Update your `.env` file with the following values, replacing the `{placeholder}` values with your actual configuration: -```text CERTIFICATE_PASSWORD="{password}" CERTIFICATE_PATH="./certs/servicecontrol.pfx" CA_BUNDLE_PATH="./certs/ca-bundle.crt" @@ -63,75 +57,276 @@ SERVICEPULSE_CLIENTID="{servicepulse-client-id}" SERVICEPULSE_APISCOPES=["api://{servicecontrol-client-id}/{scope-name}"] ``` -| Variable | Description | -|---------------------------|------------------------------------------------------------------------------------------| -| `CERTIFICATE_PASSWORD` | Password for the PFX certificate (e.g., the password used when generating with mkcert) | -| `CERTIFICATE_PATH` | Path to the PFX certificate file (e.g., `./certs/servicecontrol.pfx`) | -| `CA_BUNDLE_PATH` | Path to the CA bundle file (e.g., `./certs/ca-bundle.crt`) | -| `IDP_AUTHORITY` | Microsoft Entra ID authority URL (e.g., `https://login.microsoftonline.com/{tenant-id}`) | -| `SERVICECONTROL_AUDIENCE` | Application ID URI from ServiceControl app registration (e.g., `api://{servicecontrol-client-id}`) | -| `SERVICEPULSE_CLIENTID` | Application (client) ID from ServicePulse app registration AD | -| `SERVICEPULSE_APISCOPES` | Array of API scopes ServicePulse should request when calling ServiceControl (e.g., ["api://{servicecontrol-client-id}/{scope-name}"]) | +| Variable | Description | +|---------------------------|------------------------------------------------------------------------------------------------------------------------------------------| +| `CERTIFICATE_PASSWORD` | Password for the PFX certificate | +| `CERTIFICATE_PATH` | Path to the PFX certificate file | +| `CA_BUNDLE_PATH` | Path to a PEM file containing the CA that signed the PFX. Containers use this to verify each other's certificates over HTTPS. | +| `IDP_AUTHORITY` | Microsoft Entra ID authority URL (e.g., `https://login.microsoftonline.com/{tenant-id}`) | +| `SERVICECONTROL_AUDIENCE` | Application ID URI from ServiceControl app registration (e.g., `api://{servicecontrol-client-id}`) | +| `SERVICEPULSE_CLIENTID` | Application (client) ID from ServicePulse app registration | +| `SERVICEPULSE_APISCOPES` | Array of API scopes ServicePulse should request when calling ServiceControl (e.g., `["api://{servicecontrol-client-id}/{scope-name}"]`) | -#### Generate a PFX Certificate for Local Testing Only +#### Identity provider configuration examples -> [!WARNING] -> The certificate generated below is for local testing only. Use a certificate from a trusted Certificate Authority for production deployments. +The `.env` values for `IDP_AUTHORITY`, `SERVICECONTROL_AUDIENCE`, `SERVICEPULSE_CLIENTID`, and `SERVICEPULSE_APISCOPES` depend on which identity provider you use. + +
+Microsoft Entra ID + +Register two app registrations in [Entra ID](https://entra.microsoft.com): + +- **ServiceControl**: expose an API with an application ID URI and at least one scope +- **ServicePulse**: register as a single-page application; grant it permission to call the ServiceControl API + +IDP_AUTHORITY="https://login.microsoftonline.com/{tenant-id}" +SERVICECONTROL_AUDIENCE="api://{servicecontrol-client-id}" +SERVICEPULSE_CLIENTID="{servicepulse-client-id}" +SERVICEPULSE_APISCOPES=["api://{servicecontrol-client-id}/{scope-name}"] +``` + +
+ +
+Auth0 + +In your [Auth0 dashboard](https://manage.auth0.com): + +- **API**: create an API whose *identifier* becomes `SERVICECONTROL_AUDIENCE`. Add a permission (scope) for ServicePulse to request. +- **Application**: create a Single Page Application for ServicePulse. Add `https://localhost:9090` to *Allowed Callback URLs*, *Allowed Logout URLs*, and *Allowed Web Origins*. + +IDP_AUTHORITY="https://{tenant}.auth0.com/" +SERVICECONTROL_AUDIENCE="{api-identifier}" +SERVICEPULSE_CLIENTID="{servicepulse-application-client-id}" +SERVICEPULSE_APISCOPES=["{api-identifier}/{permission-name}"] +``` + +> [!NOTE] +> The Auth0 authority URL requires a trailing slash. + +
+ +
+Keycloak + +A `compose-secure-keycloak.yml` file is provided to run Keycloak alongside the Service Platform stack. It is configured via `.env.keycloak`. + +#### Configuring Keycloak + +Pull and start the stack, then log in to the Keycloak admin console at `https://localhost:8282` with username `admin` and password `admin`: + +```pwsh +docker compose -f compose-secure-keycloak.yml --env-file .env.keycloak pull +docker compose -f compose-secure-keycloak.yml --env-file .env.keycloak up -d +``` + +In the Keycloak admin console: + +1. **Create a realm** (e.g. `my-realm`) +2. **Create a client scope** at the realm level (e.g. `servicecontrol`) +3. **ServiceControl client**: create a client. On its dedicated client scope, add an *Audience* mapper so access tokens include the ServiceControl client ID in the `aud` claim. +4. **ServicePulse client**: create a public client with *Standard flow* and PKCE enabled. Set the valid redirect URI to `https://localhost:9090/*` and web origin to `https://localhost:9090`. Add the ServiceControl scope as an optional scope. + +#### `.env.keycloak` values + +Update `.env.keycloak` with the following, replacing the `{placeholder}` values with your Keycloak configuration: + +```text +IDP_AUTHORITY="https://localhost:8282/realms/{realm}" +SERVICECONTROL_AUDIENCE="{servicecontrol-client-id}" +SERVICEPULSE_CLIENTID="{servicepulse-client-id}" +SERVICEPULSE_APISCOPES=["{scope-name}"] +``` + +Once running, [ServicePulse](https://docs.particular.net/servicepulse/) can be accessed at https://localhost:9090. + +
+ +
+Duende IdentityServer + +In your IdentityServer configuration: + +- **ApiResource**: register a resource for ServiceControl with one or more scopes (e.g., `servicecontrol:read`). +- **Client**: register a client for ServicePulse using the `authorization_code` grant with PKCE. Grant it access to the ServiceControl scopes and set `RedirectUris` to `https://localhost:9090`. + +IDP_AUTHORITY="https://{your-identity-server}" +SERVICECONTROL_AUDIENCE="{api-resource-name}" +SERVICEPULSE_CLIENTID="{servicepulse-client-id}" +SERVICEPULSE_APISCOPES=["{api-resource-name}/{scope-name}"] +``` + +
-The below assume the `mkcert` tool has been installed. +### Generating a certificate (local testing only) + +> [!WARNING] +> The certificates generated below are for local testing only. Use a certificate from a trusted Certificate Authority for production deployments. > [!IMPORTANT] -> The certificate must include every hostname that will be used to access a service over HTTPS. In a Docker Compose network, containers reach each other using service names as hostnames (e.g., `https://servicecontrol:33333`). During the TLS handshake the client checks that the server's certificate contains a [Subject Alternative Name](https://en.wikipedia.org/wiki/Subject_Alternative_Name) (SAN) matching the hostname it connected to. If the name is missing, the connection is rejected. +> The certificate must include every hostname used to access services over HTTPS. In a Docker Compose network, containers reach each other using their service names as hostnames (e.g., `https://servicecontrol:33333`). The TLS handshake checks that the server certificate contains a [Subject Alternative Name](https://en.wikipedia.org/wiki/Subject_Alternative_Name) (SAN) matching the hostname being connected to — if a name is missing, the connection is rejected. + +#### Option 1: Using mkcert + +Install [mkcert](https://github.com/FiloSottile/mkcert): + +```pwsh +winget install FiloSottile.mkcert +``` + +Generate the certificate: ```pwsh -# Install mkcert's root CA (one-time setup) +# One-time setup: add mkcert's root CA to your system trust store mkcert -install -# Navigate/create a folder to store the certificates. e.g. +# Create the certs folder and generate a PFX covering all required hostnames mkdir certs -cd certs +mkcert -p12-file certs/servicecontrol.pfx -pkcs12 localhost 127.0.0.1 ::1 servicecontrol servicecontrol-audit servicecontrol-monitoring +``` + +> [!NOTE] +> mkcert sets the PKCS12 password to `changeit`. Set `CERTIFICATE_PASSWORD=changeit` in `.env`. + +#### Option 2: Using PowerShell (no additional tools required) + +Run the following from the `docker-compose` directory. Set `CERTIFICATE_PASSWORD=password` in `.env` (or change the password in the script and update `.env` to match). + +```pwsh +# Create a local CA +$ca = New-SelfSignedCertificate ` + -Subject "CN=LocalDevCA" ` + -KeyUsageProperty Sign ` + -KeyUsage CertSign, CRLSign, DigitalSignature ` + -TextExtension @("2.5.29.19={critical}{text}ca=TRUE") ` + -KeyExportPolicy Exportable ` + -CertStoreLocation "Cert:\CurrentUser\My" ` + -NotAfter (Get-Date).AddYears(5) + +# Create server cert signed by the CA, covering all required hostnames +$cert = New-SelfSignedCertificate ` + -Subject "CN=localhost" ` + -DnsName "localhost","servicecontrol","servicecontrol-audit","servicecontrol-monitoring" ` + -Signer $ca ` + -KeyExportPolicy Exportable ` + -CertStoreLocation "Cert:\CurrentUser\My" ` + -NotAfter (Get-Date).AddYears(2) + +New-Item -ItemType Directory -Force certs | Out-Null + +# Export the server cert as PFX +$password = ConvertTo-SecureString -String "password" -Force -AsPlainText +Export-PfxCertificate -Cert $cert -FilePath "certs\servicecontrol.pfx" -Password $password + +# Export the CA cert as PEM — this becomes the CA bundle +$caBytes = $ca.Export([System.Security.Cryptography.X509Certificates.X509ContentType]::Cert) +$caPem = "-----BEGIN CERTIFICATE-----`n" + [Convert]::ToBase64String($caBytes, "InsertLineBreaks") + "`n-----END CERTIFICATE-----" +Set-Content -Path "certs\ca-bundle.crt" -Value $caPem -Encoding ASCII + +# Remove temporary certs from the store +Remove-Item "Cert:\CurrentUser\My\$($ca.Thumbprint)" -Force +Remove-Item "Cert:\CurrentUser\My\$($cert.Thumbprint)" -Force +``` + +#### Option 3: Using OpenSSL + +> [!NOTE] +> On Windows, run these commands in Git Bash or WSL. OpenSSL 1.1.1 or later is required. + +> [!NOTE] +> On Windows with Git Bash, prefix any `openssl req` command that uses `-subj` with `MSYS_NO_PATHCONV=1` to prevent Git Bash from converting the subject path. + +```bash +mkdir -p certs + +# Generate a CA key and self-signed CA certificate +openssl genrsa -out certs/ca.key 4096 +MSYS_NO_PATHCONV=1 openssl req -x509 -new -nodes -key certs/ca.key -sha256 -days 1825 \ + -out certs/ca.crt -subj "/CN=LocalDevCA" + +# Generate a server key and certificate signing request +openssl genrsa -out certs/servicecontrol.key 2048 +MSYS_NO_PATHCONV=1 openssl req -new -key certs/servicecontrol.key -out certs/servicecontrol.csr \ + -subj "/CN=localhost" + +# Write the required SANs to a config file — run each echo separately +echo "[ext]" > /tmp/san.cnf +echo "subjectAltName=DNS:localhost,DNS:servicecontrol,DNS:servicecontrol-audit,DNS:servicecontrol-monitoring,IP:127.0.0.1" >> /tmp/san.cnf + +# Sign the server cert with the CA, including all required SANs +openssl x509 -req -in certs/servicecontrol.csr \ + -CA certs/ca.crt -CAkey certs/ca.key -CAcreateserial \ + -out certs/servicecontrol.crt -days 730 -sha256 \ + -extfile /tmp/san.cnf -extensions ext -# Generate PFX certificate for localhost/servicecontrol instances -mkcert -p12-file servicecontrol.pfx -pkcs12 localhost 127.0.0.1 ::1 servicecontrol servicecontrol-audit servicecontrol-monitoring +# Bundle into a PFX (password: "password") +openssl pkcs12 -export -out certs/servicecontrol.pfx \ + -inkey certs/servicecontrol.key -in certs/servicecontrol.crt \ + -certfile certs/ca.crt -passout pass:password + +# Use the CA cert as the CA bundle +cp certs/ca.crt certs/ca-bundle.crt + +# Remove intermediate files +rm certs/ca.key certs/servicecontrol.key certs/servicecontrol.csr certs/ca.srl ``` -#### Generate a CA Bundle for Local Testing Only +Set `CERTIFICATE_PASSWORD=password` in `.env`. The CA bundle is generated by this script — no additional step needed. + +### Generating a CA bundle (local testing only) > [!WARNING] > The CA bundle generated below is for local testing only. Use certificates from a trusted Certificate Authority for production deployments. -When running ServiceControl in Docker containers, each container needs a CA bundle file to trust certificates presented by other services. The `SSL_CERT_FILE` environment variable tells .NET where to find this bundle. +Docker containers don't share the host's certificate trust store. The CA bundle provides containers with the CA certificates they need to verify HTTPS connections to other services — including the internal healthcheck that determines whether a container is ready. Without it, containers will reject HTTPS connections and fail their healthchecks. -#### What is a CA Bundle? +#### Using mkcert -A CA bundle is a file containing one or more Certificate Authority (CA) certificates. When a container makes an HTTPS request to another service, it uses this bundle to verify the server's certificate chain. Without it, containers would reject connections to services using your mkcert certificates. Unlike your host machine (where `mkcert -install` adds the CA to the system trust store), Docker containers don't share the host's trust store. You must explicitly provide the CA certificates that containers should trust. +If you used mkcert to generate the certificate, copy its root CA as the bundle: + +```pwsh +copy "$(mkcert -CAROOT)\rootCA.pem" certs\ca-bundle.crt +``` -#### Generate the CA bundle +#### Using PowerShell + +The PowerShell script above already writes `certs\ca-bundle.crt` as part of cert generation. No additional step is needed. + +#### Using OpenSSL + +The OpenSSL script above already writes `certs/ca-bundle.crt` as part of cert generation. No additional step is needed. + +### Pull the latest images + +Before running the containers, ensure you're using the latest version of each image: ```pwsh -# Get the mkcert CA root location -$CA_ROOT = mkcert -CAROOT +docker compose -f compose-secure.yml pull +``` -# Navigate to the folder containing the PFX certificate -cd certs +### Start the containers -# For local development only (just mkcert CA) -copy "$CA_ROOT/rootCA.pem" ca-bundle.crt +```pwsh +docker compose -f compose-secure.yml up -d ``` - ### Pull the latest images - Before running the containers, ensure you're using the latest version of each image by executing the following command: +Once running, [ServicePulse](https://docs.particular.net/servicepulse/) can be accessed at https://localhost:9090. + +### Troubleshooting - ```pwsh - docker compose -f compose-secure.yml pull - ``` +#### Container is unhealthy but logs show no errors -### Starting the secure containers +Docker's healthcheck output is separate from container logs. To see the actual failure reason: ```pwsh -docker compose -f compose-secure.yml up -d +docker inspect --format='{{json .State.Health}}' service-platform-servicecontrol-1 ``` -Once composed: +Common causes and fixes: -- [ServicePulse](https://docs.particular.net/servicepulse/) can be accessed at https://localhost:9090 +| Error | Cause | Fix | +|---|---|---| +| `UntrustedRoot` | CA bundle is empty or doesn't contain the CA that signed the PFX | Verify `certs\ca-bundle.crt` is non-empty and was generated from the same CA used to sign the PFX | +| `The SSL connection could not be established` | Certificate is missing a required SAN (e.g., `localhost`) or the PFX file is invalid | Regenerate the certificate ensuring all hostnames are included | +| File not found / empty cert | `CERTIFICATE_PATH` in `.env` points to a file that doesn't exist | Check the path is correct and the file exists on the host before starting containers | +| `AuthenticationException` | `CERTIFICATE_PASSWORD` in `.env` doesn't match the password used to generate the PFX | Update `CERTIFICATE_PASSWORD` to match (mkcert uses `changeit` by default) | diff --git a/docker-compose/compose-secure-keycloak.yml b/docker-compose/compose-secure-keycloak.yml new file mode 100644 index 0000000..75758e0 --- /dev/null +++ b/docker-compose/compose-secure-keycloak.yml @@ -0,0 +1,183 @@ +name: service-platform + +services: + servicecontrol: + image: particular/servicecontrol:${SERVICECONTROL_TAG} + env_file: .env + ports: + - "33333:33333" + environment: + RAVENDB_CONNECTIONSTRING: http://servicecontrol-db:8080 + REMOTEINSTANCES: '[{"api_uri":"https://servicecontrol-audit:44444/api"}]' + SERVICECONTROL_HTTPS_ENABLED: "true" + SERVICECONTROL_HTTPS_CERTIFICATEPATH: "/usr/share/ParticularSoftware/certificate.pfx" + SERVICECONTROL_HTTPS_CERTIFICATEPASSWORD: "${CERTIFICATE_PASSWORD}" + SSL_CERT_FILE: "/etc/ssl/certs/ca-bundle.crt" + SERVICECONTROL_AUTHENTICATION_ENABLED: "true" + SERVICECONTROL_AUTHENTICATION_AUTHORITY: "${IDP_AUTHORITY}" + SERVICECONTROL_AUTHENTICATION_AUDIENCE: "${SERVICECONTROL_AUDIENCE}" + SERVICECONTROL_AUTHENTICATION_SERVICEPULSE_CLIENTID: "${SERVICEPULSE_CLIENTID}" + SERVICECONTROL_AUTHENTICATION_SERVICEPULSE_AUTHORITY: "${IDP_AUTHORITY}" + SERVICECONTROL_AUTHENTICATION_SERVICEPULSE_APISCOPES: '${SERVICEPULSE_APISCOPES}' + command: --setup-and-run + restart: unless-stopped + volumes: + - ${CERTIFICATE_PATH}:/usr/share/ParticularSoftware/certificate.pfx + - ${CA_BUNDLE_PATH}:/etc/ssl/certs/ca-bundle.crt:ro + healthcheck: + test: ["CMD", "/healthcheck/healthcheck", "https://localhost:33333/api"] + interval: 30s + timeout: 10s + start_period: 60s + retries: 3 + depends_on: + servicecontrol-db: + condition: service_healthy + rabbitmq: + condition: service_healthy + keycloak: + condition: service_healthy + + # WARNING: A single database container should not be shared between multiple ServiceControl instances in production scenarios. + servicecontrol-db: + image: particular/servicecontrol-ravendb:${SERVICECONTROL_TAG} + ports: + - "8080:8080" + volumes: + - raven-config:/var/lib/ravendb/config + - raven-data:/var/lib/ravendb/data + + servicecontrol-audit: + image: particular/servicecontrol-audit:${SERVICECONTROL_TAG} + env_file: .env + ports: + - "44444:44444" + environment: + RAVENDB_CONNECTIONSTRING: http://servicecontrol-db:8080 + SERVICECONTROLQUEUEADDRESS: Particular.ServiceControl + SERVICECONTROL_AUDIT_HTTPS_ENABLED: "true" + SERVICECONTROL_AUDIT_HTTPS_CERTIFICATEPATH: "/usr/share/ParticularSoftware/certificate.pfx" + SERVICECONTROL_AUDIT_HTTPS_CERTIFICATEPASSWORD: "${CERTIFICATE_PASSWORD}" + SSL_CERT_FILE: "/etc/ssl/certs/ca-bundle.crt" + SERVICECONTROL_AUDIT_AUTHENTICATION_ENABLED: "true" + SERVICECONTROL_AUDIT_AUTHENTICATION_AUTHORITY: "${IDP_AUTHORITY}" + SERVICECONTROL_AUDIT_AUTHENTICATION_AUDIENCE: "${SERVICECONTROL_AUDIENCE}" + command: --setup-and-run + restart: unless-stopped + volumes: + - ${CERTIFICATE_PATH}:/usr/share/ParticularSoftware/certificate.pfx + - ${CA_BUNDLE_PATH}:/etc/ssl/certs/ca-bundle.crt:ro + healthcheck: + test: ["CMD", "/healthcheck/healthcheck", "https://localhost:44444/api"] + interval: 30s + timeout: 10s + start_period: 60s + retries: 3 + depends_on: + servicecontrol-db: + condition: service_healthy + rabbitmq: + condition: service_healthy + keycloak: + condition: service_healthy + + servicecontrol-monitoring: + image: particular/servicecontrol-monitoring:${SERVICECONTROL_TAG} + env_file: .env + environment: + MONITORING_HTTPS_ENABLED: "true" + MONITORING_HTTPS_CERTIFICATEPATH: "/usr/share/ParticularSoftware/certificate.pfx" + MONITORING_HTTPS_CERTIFICATEPASSWORD: "${CERTIFICATE_PASSWORD}" + SSL_CERT_FILE: "/etc/ssl/certs/ca-bundle.crt" + MONITORING_AUTHENTICATION_ENABLED: "true" + MONITORING_AUTHENTICATION_AUTHORITY: "${IDP_AUTHORITY}" + MONITORING_AUTHENTICATION_AUDIENCE: "${SERVICECONTROL_AUDIENCE}" + restart: unless-stopped + command: --setup-and-run + ports: + - "33633:33633" + volumes: + - ${CERTIFICATE_PATH}:/usr/share/ParticularSoftware/certificate.pfx + - ${CA_BUNDLE_PATH}:/etc/ssl/certs/ca-bundle.crt:ro + healthcheck: + test: ["CMD", "/healthcheck/healthcheck", "https://localhost:33633/"] + interval: 30s + timeout: 10s + start_period: 60s + retries: 3 + depends_on: + rabbitmq: + condition: service_healthy + keycloak: + condition: service_healthy + + servicepulse: + image: particular/servicepulse:${SERVICEPULSE_TAG} + ports: + - "9090:9090" + environment: + SERVICECONTROL_URL: https://servicecontrol:33333 + MONITORING_URL: https://servicecontrol-monitoring:33633 + SERVICEPULSE_HTTPS_ENABLED: "true" + SERVICEPULSE_HTTPS_CERTIFICATEPATH: "/usr/share/ParticularSoftware/certificate.pfx" + SERVICEPULSE_HTTPS_CERTIFICATEPASSWORD: "${CERTIFICATE_PASSWORD}" + SSL_CERT_FILE: "/etc/ssl/certs/ca-bundle.crt" + ASPNETCORE_URLS: "https://+:9090" + restart: unless-stopped + volumes: + - ${CERTIFICATE_PATH}:/usr/share/ParticularSoftware/certificate.pfx + - ${CA_BUNDLE_PATH}:/etc/ssl/certs/ca-bundle.crt:ro + depends_on: + servicecontrol: + condition: service_healthy + servicecontrol-monitoring: + condition: service_healthy + rabbitmq: + condition: service_healthy + keycloak: + condition: service_healthy + + keycloak: + image: quay.io/keycloak/keycloak:latest + ports: + - "8282:8443" + environment: + KC_BOOTSTRAP_ADMIN_USERNAME: admin + KC_BOOTSTRAP_ADMIN_PASSWORD: admin + KC_HEALTH_ENABLED: "true" + KC_HTTPS_KEY_STORE_FILE: /opt/keycloak/conf/certificate.pfx + KC_HTTPS_KEY_STORE_PASSWORD: "${CERTIFICATE_PASSWORD}" + KC_HTTPS_KEY_STORE_TYPE: PKCS12 + command: start-dev + restart: unless-stopped + volumes: + - ${CERTIFICATE_PATH}:/opt/keycloak/conf/certificate.pfx:ro + - keycloak-data:/opt/keycloak/data + healthcheck: + test: ["CMD-SHELL", "bash -c 'exec 3<>/dev/tcp/localhost/9000'"] + interval: 30s + timeout: 10s + start_period: 90s + retries: 3 + + rabbitmq: + image: rabbitmq:3-management + ports: + - "5672:5672" + - "15672:15672" + restart: unless-stopped + healthcheck: + test: rabbitmq-diagnostics check_port_connectivity + interval: 30s + timeout: 10s + start_period: 30s + start_interval: 10s + retries: 3 + volumes: + - rabbitmq-data:/var/lib/rabbitmq + +volumes: + rabbitmq-data: + raven-config: + raven-data: + keycloak-data: