This repository was archived by the owner on Mar 10, 2026. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 3
feat: mTLS for Manager ↔ Decision Maker communication #16
Merged
Merged
Changes from all commits
Commits
Show all changes
7 commits
Select commit
Hold shift + click to select a range
01e65f5
Initial plan
Copilot 84512b4
feat: add mTLS support for Manager ↔ Decision Maker communication
Copilot 36119a3
Update rest_app.go
ianchen0119 a0dbbb5
chore: Update rest_app.go
ianchen0119 4ab7dd3
Update deicison_maker.go
ianchen0119 a0ba103
chore: Update deicison_maker.go
ianchen0119 c423f84
fix: update deicison_maker_test.go
ianchen0119 File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -239,6 +239,13 @@ client_id = "your-client-id" | |
| [account] | ||
| admin_email = "[email protected]" | ||
| admin_password = "your-password" | ||
|
|
||
| # mTLS for Manager → Decision Maker communication (optional, default: disabled) | ||
| [mtls] | ||
| enable = false | ||
| cert_pem = "..." # Manager's client certificate (signed by private CA) | ||
| key_pem = "..." # Manager's client private key | ||
| ca_pem = "..." # Private CA certificate (to verify Decision Maker's server cert) | ||
| ``` | ||
|
|
||
| #### Decision Maker Configuration (`config/dm_config.toml`) | ||
|
|
@@ -252,6 +259,13 @@ level = "info" | |
| [token] | ||
| rsa_private_key_pem = "..." | ||
| token_duration_hr = 24 | ||
|
|
||
| # mTLS server for Manager → Decision Maker communication (optional, default: disabled) | ||
| [mtls] | ||
| enable = false | ||
| cert_pem = "..." # Decision Maker's server certificate (signed by private CA) | ||
| key_pem = "..." # Decision Maker's server private key | ||
| ca_pem = "..." # Private CA certificate (to verify Manager's client cert) | ||
| ``` | ||
|
|
||
| ### 3. Start Services | ||
|
|
@@ -276,6 +290,148 @@ go run main.go decisionmaker -c dm_config -d /path/to/config | |
|
|
||
| Please refer to https://github.com/Gthulhu/chart?tab=readme-ov-file#testing for testing the API endpoints using curl. | ||
|
|
||
| ## mTLS Setup: Manager ↔ Decision Maker | ||
|
|
||
| The Manager communicates with every Decision Maker node using **mutual TLS (mTLS)**. Both sides authenticate each other with certificates signed by a shared **private CA**, so neither plain-text traffic nor untrusted connections are accepted. | ||
|
|
||
| > **Note**: The Manager's external HTTP API (web GUI, `/api/v1/…`) intentionally remains plain HTTP. In a production cluster this endpoint is typically exposed through a Kubernetes Ingress with TLS termination. | ||
|
|
||
| ### Why mTLS? | ||
|
|
||
| Scheduling decisions affect the Linux kernel scheduler on every node. A compromised connection between the Manager and a Decision Maker could allow an attacker to manipulate per-process CPU priorities. mTLS provides: | ||
|
|
||
| - **Server authentication** – the Manager verifies it is talking to a genuine Decision Maker. | ||
| - **Client authentication** – the Decision Maker verifies only the authorised Manager can push intents. | ||
| - **Encrypted channel** – all scheduling intents are protected in transit. | ||
|
|
||
| ### Step-by-step: Generate certificates with a private CA | ||
|
|
||
| The commands below use only the OpenSSL CLI. Replace `<DM_IP>` with the actual IP or hostname of each Decision Maker node. | ||
|
|
||
| #### 1. Create the private CA | ||
|
|
||
| ```bash | ||
| # Generate CA private key (EC P-256 recommended; RSA-4096 also works) | ||
| openssl ecparam -name prime256v1 -genkey -noout -out ca.key | ||
|
|
||
| # Self-signed CA certificate (10-year validity) | ||
| openssl req -new -x509 -days 3650 \ | ||
| -key ca.key \ | ||
| -out ca.crt \ | ||
| -subj "/CN=Gthulhu-Private-CA" | ||
| ``` | ||
|
|
||
| #### 2. Generate the Manager client certificate | ||
|
|
||
| ```bash | ||
| # Manager private key | ||
| openssl ecparam -name prime256v1 -genkey -noout -out manager.key | ||
|
|
||
| # Certificate signing request | ||
| openssl req -new \ | ||
| -key manager.key \ | ||
| -out manager.csr \ | ||
| -subj "/CN=gthulhu-manager" | ||
|
|
||
| # Sign with the private CA (2-year validity, client-auth EKU) | ||
| openssl x509 -req -days 730 \ | ||
| -in manager.csr \ | ||
| -CA ca.crt -CAkey ca.key -CAcreateserial \ | ||
| -extfile <(printf "extendedKeyUsage=clientAuth") \ | ||
| -out manager.crt | ||
| ``` | ||
|
|
||
| #### 3. Generate a Decision Maker server certificate | ||
|
|
||
| Repeat for each DM node, setting the correct IP/DNS in `subjectAltName`. | ||
|
|
||
| ```bash | ||
| # Decision Maker private key | ||
| openssl ecparam -name prime256v1 -genkey -noout -out dm.key | ||
|
|
||
| # CSR | ||
| openssl req -new \ | ||
| -key dm.key \ | ||
| -out dm.csr \ | ||
| -subj "/CN=gthulhu-decisionmaker" | ||
|
|
||
| # Sign with the private CA (2-year validity, server-auth + client-auth EKUs + SAN) | ||
| openssl x509 -req -days 730 \ | ||
| -in dm.csr \ | ||
| -CA ca.crt -CAkey ca.key -CAcreateserial \ | ||
| -extfile <(printf "subjectAltName=IP:<DM_IP>\nextendedKeyUsage=serverAuth,clientAuth") \ | ||
| -out dm.crt | ||
| ``` | ||
|
|
||
| #### 4. Embed certificates in configuration | ||
|
|
||
| Paste the PEM file contents into the respective config files. | ||
|
|
||
| **`config/manager_config.toml`** | ||
|
|
||
| ```toml | ||
| [mtls] | ||
| enable = true | ||
| cert_pem = """ | ||
| -----BEGIN CERTIFICATE----- | ||
| <contents of manager.crt> | ||
| -----END CERTIFICATE----- | ||
| """ | ||
| key_pem = """ | ||
| -----BEGIN EC PRIVATE KEY----- | ||
| <contents of manager.key> | ||
| -----END EC PRIVATE KEY----- | ||
| """ | ||
| ca_pem = """ | ||
| -----BEGIN CERTIFICATE----- | ||
| <contents of ca.crt> | ||
| -----END CERTIFICATE----- | ||
| """ | ||
| ``` | ||
|
|
||
| **`config/dm_config.toml`** | ||
|
|
||
| ```toml | ||
| [mtls] | ||
| enable = true | ||
| cert_pem = """ | ||
| -----BEGIN CERTIFICATE----- | ||
| <contents of dm.crt> | ||
| -----END CERTIFICATE----- | ||
| """ | ||
| key_pem = """ | ||
| -----BEGIN EC PRIVATE KEY----- | ||
| <contents of dm.key> | ||
| -----END EC PRIVATE KEY----- | ||
| """ | ||
| ca_pem = """ | ||
| -----BEGIN CERTIFICATE----- | ||
| <contents of ca.crt> | ||
| -----END CERTIFICATE----- | ||
| """ | ||
| ``` | ||
|
|
||
| #### 5. Verify | ||
|
|
||
| Start both services and confirm the Decision Maker log contains: | ||
|
|
||
| ``` | ||
| starting dm server with mTLS on port :8080 | ||
| ``` | ||
|
|
||
| And the Manager log shows successful intent reconciliation without TLS errors. | ||
|
|
||
| ### Kubernetes: mounting certificates as Secrets | ||
|
|
||
| In a production deployment, store PEM content in Kubernetes Secrets and mount them as environment variables or files, then reference them in the TOML config. | ||
|
|
||
| ```bash | ||
| kubectl create secret generic gthulhu-mtls-certs \ | ||
| --from-file=ca.crt \ | ||
| --from-file=manager.crt \ | ||
| --from-file=manager.key | ||
| ``` | ||
|
|
||
| ## Kubernetes Deployment | ||
|
|
||
| ### Deployment Architecture | ||
|
|
||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.