Skip to content

chore(controlplane): Allow to setup NATS token based authentication #1944

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Apr 3, 2025

Conversation

javirln
Copy link
Member

@javirln javirln commented Apr 2, 2025

This patch updates the control plane server configuration to optionally accept a NATS authentication token for client connections to the NATS server. Additionally, the chart templates have been modified to support passing the token via the new controlplane.nats.token configuration option.

Signed-off-by: Javier Rodriguez <javier@chainloop.dev>
@javirln javirln requested review from migmartri and jiparis April 2, 2025 16:22
@javirln javirln self-assigned this Apr 2, 2025
// TODO: add authentication options
oneof authentication {
// Token based authentication
string token = 2 [(buf.validate.field).string.min_len = 1];
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

out of curiosity, would this force us to use token or can the current deployments keep working?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

From the tests that I could run, since the authentication field is optional, nothing will happen. The validation on the token happens if the token field is in place. Some examples:

With this configuration no token is set:

server:
  http:
    addr: 0.0.0.0:8000
    timeout: 10s
  http_metrics:
    addr: 0.0.0.0:0
  grpc:
    addr: 0.0.0.0:9000

# Way more configuration here

nats_server:
 uri: nats://0.0.0.0:4222

We can run the server:

go run ./cmd/... --conf ./configs
DEBUG msg=config loaded: config.devel.yaml format: yaml
2025-04-03T10:48:17.690+0200    INFO    {"component": "credentials/vault", "msg": "configuring vault", "address": "http://0.0.0.0:8200", "mount_path": "secret", "prefix": "chainloop-devel", "role": "writer"}
2025-04-03T10:48:17.698+0200    INFO    {"component": "plugins", "msg": "loading plugins", "dir": "./plugins/bin", "pattern": "chainloop-plugin-*"}
2025-04-03T10:48:17.698+0200    INFO    {"component": "plugins", "msg": "loaded", "type": "built-in", "plugin": "id=dependency-track, version=1.6, expectedMaterials=[SBOM_CYCLONEDX_JSON]"}
2025-04-03T10:48:17.698+0200    INFO    {"component": "plugins", "msg": "loaded", "type": "built-in", "plugin": "id=smtp, version=1.0, expectedMaterials=[]"}
2025-04-03T10:48:17.698+0200    INFO    {"component": "plugins", "msg": "loaded", "type": "built-in", "plugin": "id=discord-webhook, version=1.1, expectedMaterials=[]"}
2025-04-03T10:48:17.698+0200    INFO    {"component": "plugins", "msg": "loaded", "type": "built-in", "plugin": "id=guac, version=1.0, expectedMaterials=[SBOM_CYCLONEDX_JSON SBOM_SPDX_JSON]"}
2025-04-03T10:48:17.698+0200    INFO    {"component": "plugins", "msg": "loaded", "type": "built-in", "plugin": "id=slack-webhook, version=1.0, expectedMaterials=[]"}
2025-04-03T10:48:17.698+0200    INFO    {"component": "plugins", "msg": "loaded", "type": "built-in", "plugin": "id=webhook, version=1.0, expectedMaterials=[SBOM_CYCLONEDX_JSON SBOM_SPDX_JSON]"}
2025-04-03T10:48:17.731+0200    INFO    {"component": "natsAuditLogPublisher", "msg": "Stream Created or Updated", "name": "chainloop-audit", "subject": "audit.>"}

For all the following cases the NATS does not have any authentication configured.

Now let's add a token to the connection:

server:
  http:
    addr: 0.0.0.0:8000
    timeout: 10s
  http_metrics:
    addr: 0.0.0.0:0
  grpc:
    addr: 0.0.0.0:9000

# Way more configuration here

nats_server:
 uri: nats://0.0.0.0:4222
 token: "notasecret"
go run ./cmd/... --conf ./configs
DEBUG msg=config loaded: config.devel.yaml format: yaml
2025-04-03T10:49:26.621+0200    INFO    {"component": "credentials/vault", "msg": "configuring vault", "address": "http://0.0.0.0:8200", "mount_path": "secret", "prefix": "chainloop-devel", "role": "writer"}
2025-04-03T10:49:26.632+0200    INFO    {"component": "plugins", "msg": "loading plugins", "dir": "./plugins/bin", "pattern": "chainloop-plugin-*"}
2025-04-03T10:49:26.632+0200    INFO    {"component": "plugins", "msg": "loaded", "type": "built-in", "plugin": "id=dependency-track, version=1.6, expectedMaterials=[SBOM_CYCLONEDX_JSON]"}
2025-04-03T10:49:26.632+0200    INFO    {"component": "plugins", "msg": "loaded", "type": "built-in", "plugin": "id=smtp, version=1.0, expectedMaterials=[]"}
2025-04-03T10:49:26.632+0200    INFO    {"component": "plugins", "msg": "loaded", "type": "built-in", "plugin": "id=discord-webhook, version=1.1, expectedMaterials=[]"}
2025-04-03T10:49:26.632+0200    INFO    {"component": "plugins", "msg": "loaded", "type": "built-in", "plugin": "id=guac, version=1.0, expectedMaterials=[SBOM_CYCLONEDX_JSON SBOM_SPDX_JSON]"}
2025-04-03T10:49:26.632+0200    INFO    {"component": "plugins", "msg": "loaded", "type": "built-in", "plugin": "id=slack-webhook, version=1.0, expectedMaterials=[]"}
2025-04-03T10:49:26.632+0200    INFO    {"component": "plugins", "msg": "loaded", "type": "built-in", "plugin": "id=webhook, version=1.0, expectedMaterials=[SBOM_CYCLONEDX_JSON SBOM_SPDX_JSON]"}
2025-04-03T10:49:26.648+0200    INFO    {"component": "natsAuditLogPublisher", "msg": "Stream Created or Updated", "name": "chainloop-audit", "subject": "audit.>"}

The server starts correctly. If we now, leave the token property set and empty:

server:
  http:
    addr: 0.0.0.0:8000
    timeout: 10s
  http_metrics:
    addr: 0.0.0.0:0
  grpc:
    addr: 0.0.0.0:9000

# Way more configuration here

nats_server:
 uri: nats://0.0.0.0:4222
 token: ""
go run ./cmd/... --conf ./configs
DEBUG msg=config loaded: config.devel.yaml format: yaml
panic: validation error:
         - nats_server.token: value length must be at least 1 characters [string.min_len]

Let's activate the NATS authentication and try without token:

server:
  http:
    addr: 0.0.0.0:8000
    timeout: 10s
  http_metrics:
    addr: 0.0.0.0:0
  grpc:
    addr: 0.0.0.0:9000

# Way more configuration here

nats_server:
 uri: nats://0.0.0.0:4222
go run ./cmd/... --conf ./configs
DEBUG msg=config loaded: config.devel.yaml format: yaml
2025-04-03T10:56:11.060+0200    INFO    {"component": "credentials/vault", "msg": "configuring vault", "address": "http://0.0.0.0:8200", "mount_path": "secret", "prefix": "chainloop-devel", "role": "writer"}
2025-04-03T10:56:11.068+0200    INFO    {"component": "plugins", "msg": "loading plugins", "dir": "./plugins/bin", "pattern": "chainloop-plugin-*"}
2025-04-03T10:56:11.068+0200    INFO    {"component": "plugins", "msg": "loaded", "type": "built-in", "plugin": "id=dependency-track, version=1.6, expectedMaterials=[SBOM_CYCLONEDX_JSON]"}
2025-04-03T10:56:11.068+0200    INFO    {"component": "plugins", "msg": "loaded", "type": "built-in", "plugin": "id=smtp, version=1.0, expectedMaterials=[]"}
2025-04-03T10:56:11.068+0200    INFO    {"component": "plugins", "msg": "loaded", "type": "built-in", "plugin": "id=discord-webhook, version=1.1, expectedMaterials=[]"}
2025-04-03T10:56:11.068+0200    INFO    {"component": "plugins", "msg": "loaded", "type": "built-in", "plugin": "id=guac, version=1.0, expectedMaterials=[SBOM_CYCLONEDX_JSON SBOM_SPDX_JSON]"}
2025-04-03T10:56:11.068+0200    INFO    {"component": "plugins", "msg": "loaded", "type": "built-in", "plugin": "id=slack-webhook, version=1.0, expectedMaterials=[]"}
2025-04-03T10:56:11.068+0200    INFO    {"component": "plugins", "msg": "loaded", "type": "built-in", "plugin": "id=webhook, version=1.0, expectedMaterials=[SBOM_CYCLONEDX_JSON SBOM_SPDX_JSON]"}
2025-04-03T10:56:11.087+0200    INFO    {"msg": "closing the data resources"}
panic: failed to connect to nats: nats: Authorization Violation

With token:

server:
  http:
    addr: 0.0.0.0:8000
    timeout: 10s
  http_metrics:
    addr: 0.0.0.0:0
  grpc:
    addr: 0.0.0.0:9000

# Way more configuration here

nats_server:
 uri: nats://0.0.0.0:4222
 token: "notasecret"
go run ./cmd/... --conf ./configs
DEBUG msg=config loaded: config.devel.yaml format: yaml
2025-04-03T10:57:51.161+0200    INFO    {"component": "credentials/vault", "msg": "configuring vault", "address": "http://0.0.0.0:8200", "mount_path": "secret", "prefix": "chainloop-devel", "role": "writer"}
2025-04-03T10:57:51.170+0200    INFO    {"component": "plugins", "msg": "loading plugins", "dir": "./plugins/bin", "pattern": "chainloop-plugin-*"}
2025-04-03T10:57:51.171+0200    INFO    {"component": "plugins", "msg": "loaded", "type": "built-in", "plugin": "id=dependency-track, version=1.6, expectedMaterials=[SBOM_CYCLONEDX_JSON]"}
2025-04-03T10:57:51.171+0200    INFO    {"component": "plugins", "msg": "loaded", "type": "built-in", "plugin": "id=smtp, version=1.0, expectedMaterials=[]"}
2025-04-03T10:57:51.171+0200    INFO    {"component": "plugins", "msg": "loaded", "type": "built-in", "plugin": "id=discord-webhook, version=1.1, expectedMaterials=[]"}
2025-04-03T10:57:51.171+0200    INFO    {"component": "plugins", "msg": "loaded", "type": "built-in", "plugin": "id=guac, version=1.0, expectedMaterials=[SBOM_CYCLONEDX_JSON SBOM_SPDX_JSON]"}
2025-04-03T10:57:51.171+0200    INFO    {"component": "plugins", "msg": "loaded", "type": "built-in", "plugin": "id=slack-webhook, version=1.0, expectedMaterials=[]"}
2025-04-03T10:57:51.171+0200    INFO    {"component": "plugins", "msg": "loaded", "type": "built-in", "plugin": "id=webhook, version=1.0, expectedMaterials=[SBOM_CYCLONEDX_JSON SBOM_SPDX_JSON]"}
2025-04-03T10:57:51.195+0200    INFO    {"component": "natsAuditLogPublisher", "msg": "Stream Created or Updated", "name": "chainloop-audit", "subject": "audit.>"}

Basically the key here is not rendering the token field on the nats_server configuration object if there is no authentication.

This is the default configuration being rendered if the token value is not passed:

stringData:
  config.secret.yaml: |
    data:
      database:
        driver: pgx
        source: postgresql://chainloop:chainlooppwd@chainloop-postgresql:5432/chainloop-cp
    nats_server: 
      uri: "nats://aaa:4222"

    credentials_service:      
      secretPrefix: "chainloop"
      vault:
        address: "http://chainloop-vault-server:8200"
        token: "notasecret"

If we pass a token with --set controlplane.nats.token="notasecret"

stringData:
  config.secret.yaml: |
    data:
      database:
        driver: pgx
        source: postgresql://chainloop:chainlooppwd@chainloop-postgresql:5432/chainloop-cp
    nats_server: 
      uri: "nats://aaa:4222"
      token: "notasecret"

    credentials_service:      
      secretPrefix: "chainloop"
      vault:
        address: "http://chainloop-vault-server:8200"
        token: "notasecret"

If we pass an empty token, --set controlplane.nats.token="", it will simply not render:

stringData:
  config.secret.yaml: |
    data:
      database:
        driver: pgx
        source: postgresql://chainloop:chainlooppwd@chainloop-postgresql:5432/chainloop-cp
    nats_server: 
      uri: "nats://aaa:4222"

    credentials_service:      
      secretPrefix: "chainloop"
      vault:
        address: "http://chainloop-vault-server:8200"
        token: "notasecret"

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

so about the rollout, if we add the token to the clients but not to the server, would it work?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, that's the second example, the NATS server will ignore the authentication token if it does not have any configured.

@javirln javirln merged commit bb1159c into chainloop-dev:main Apr 3, 2025
13 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants