Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
77 commits
Select commit Hold shift + click to select a range
7054064
Set TLS 1.2 minimum for all endpoints
Dec 18, 2020
1f95be7
Return an error if an SDS client asks for resources that don't exist.
JonathanO Dec 15, 2020
c14ae77
Please the linter.
JonathanO Dec 15, 2020
c68ba66
Code review fixes.
JonathanO Jan 8, 2021
d7c87a7
Log errors in failed user/group name lookup in unix workload attestor
Jan 8, 2021
dc4412b
Fix capitalization of logs
Jan 13, 2021
3a11c54
Test that logs are emitted from unix workload attestor plugin
Jan 13, 2021
3f63656
Implement the readiness endpoint for health checking
ryysud Nov 27, 2020
5ac72bc
Remove the checking_readiness_interval parameter
ryysud Jan 13, 2021
2e9d5be
Avoid the gRPC connection leaks in the health system
ryysud Jan 13, 2021
e649bae
Update the bind_port in the health_checks block example
ryysud Jan 13, 2021
a47a30b
Fix suites/k8s-reconcile
ryysud Jan 13, 2021
5d8bd42
Address PR comments
ryysud Jan 16, 2021
bb12dfb
adds a 30 seconds timeout to keymanager plugin calls
kunzimariano Jan 11, 2021
49394a0
Report uptime as metrics for spire server and agent with config (#2032)
hixichen Jan 21, 2021
24ab4ca
Return an error when having an expired SVID when rotating the agent S…
amartinezfayo Jan 25, 2021
4363298
Fix error tracking for entry cache telemetry
Jan 29, 2021
b2b9c0d
Fix Vault token auth bug (#2110)
Feb 25, 2021
25959c4
Fixes #2026 - thanks @caleblloyd!
Feb 17, 2021
0b869eb
Issue #2026 - Unit tests
Feb 17, 2021
cdf4044
Clarify docs
Feb 17, 2021
68ff24e
Review comment - map is there to prevent dupes
Feb 22, 2021
bd5c1ab
Comment wording was unnecessarily confusing
Mar 9, 2021
23d5dbc
show selectors
Mar 4, 2021
3e2157f
fixup! show selectors
Mar 8, 2021
c3d5bb3
Expose a configuration to disable rate limiting on JWT signing and X5…
amartinezfayo Mar 11, 2021
7a43631
Use SPIRE to rotate webhook certificates
Dec 11, 2020
7b90b30
Stop using previous object for patch
Jan 5, 2021
d4733a9
Add missing mutating webhook patches
Jan 5, 2021
d501c38
Collapse ConfigMap
Jan 5, 2021
bcd6ae4
fix watcher
Jan 7, 2021
5d995c5
Run gofmt
Jan 7, 2021
2539a6f
Make watcher dynamically configurable
Jan 8, 2021
9c6e7d3
minor cleanup
Jan 8, 2021
685ff01
Fix test and lint errors
Jan 8, 2021
d6f210c
Add first unit test
Jan 9, 2021
ee97f90
unit test, cleanup watcher
Jan 13, 2021
b38997b
Move watcher to its own file
Jan 14, 2021
ff39dec
Fix unit test failures
Jan 15, 2021
19b8c1d
Fix linter errors
Jan 15, 2021
c740f88
More unit tests, some cleanup
Jan 16, 2021
78b7ad2
Restore some comments that shouldn't have been removed
Jan 16, 2021
724b1ad
Add unit test, more cleanup
Jan 16, 2021
461c145
Fix race conditions
Jan 19, 2021
0e6cb1f
Update docs
Jan 20, 2021
61f838f
Fix docs typo
Jan 20, 2021
287919b
Change config from webhook_label to label to make it more generic
Jan 27, 2021
2d03d34
Fix race condition in TestBundleWatcherUpdateConfig test
Feb 12, 2021
3aaf279
Fix race condition in TestBundleWatcherAddEvent, rename watcherEvent
Feb 12, 2021
7fb2bc9
Lock to RWLock
faisal-memon Feb 25, 2021
fb43220
Continue updating bundles if one gets error
Feb 26, 2021
df24656
Fix unit test errors
Feb 26, 2021
d626e66
Remove start/stop pattern
Mar 3, 2021
e820179
Remove validWatcherPresent bool
Mar 3, 2021
a530844
Some cleanup
Mar 4, 2021
16300bc
label -> webhook_label
faisal-memon Mar 5, 2021
f7da1ba
label -> webhook_label part 2
Mar 5, 2021
4c75609
Fix setConfig error handling
Mar 5, 2021
424dbca
Update docs for webhook_label
Mar 5, 2021
7dc0adf
Fix setConfig ordering
Mar 5, 2021
d2bacac
Aggregate errors
Mar 6, 2021
a574ff9
Aggregate error messages, add comment
Mar 8, 2021
b76e8f3
Remove nil watchers
Mar 8, 2021
5992d14
Cleanup unit tests
Mar 8, 2021
965f307
Set cancelWatcher to nil after calling it
Mar 9, 2021
42f1ddb
Ignore FailedPrecondition errors
Mar 10, 2021
3c621e9
Don't log when FailedPrecondition error happens
Mar 10, 2021
7fe7e9c
Handle webhook modified case
Mar 10, 2021
7f74e03
Fix MySQL isolation level for read-modify-write ops
Mar 12, 2021
b0515de
change updateAttestedNodes tx type
Mar 12, 2021
0afaec1
Fix spiffe ID equality
Mar 15, 2021
01857ed
Introduce a new aws_iid plugin configuration option 'use_instance_pro…
kgtw Feb 18, 2021
48495cb
Change config to 'disable_instance_profile_selectors' to maintain bac…
kgtw Feb 18, 2021
663008a
Update aws_iid documentation for disable_instance_profile_selectors c…
kgtw Mar 5, 2021
6c9ff28
Update aws_iid documentation with more context around the disable_ins…
kgtw Mar 12, 2021
38845c4
Fix wording in documentation for disable_instance_profile_selectors
kgtw Mar 12, 2021
2ed56a7
Include the attestor type in the error returned when could not find t…
amartinezfayo Mar 17, 2021
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 18 additions & 1 deletion cmd/spire-server/cli/agent/agent_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,17 @@ import (
)

var (
testAgents = []*types.Agent{{Id: &types.SPIFFEID{TrustDomain: "example.org", Path: "/spire/agent/agent1"}}}
testAgents = []*types.Agent{{Id: &types.SPIFFEID{TrustDomain: "example.org", Path: "/spire/agent/agent1"}}}
testAgentsWithSelectors = []*types.Agent{
{
Id: &types.SPIFFEID{TrustDomain: "example.org", Path: "/spire/agent/agent2"},
Selectors: []*types.Selector{
{Type: "k8s_psat", Value: "agent_ns:spire"},
{Type: "k8s_psat", Value: "agent_sa:spire-agent"},
{Type: "k8s_psat", Value: "cluster:demo-cluster"},
},
},
}
)

type agentTest struct {
Expand Down Expand Up @@ -205,6 +215,13 @@ func TestShow(t *testing.T) {
expectedReturnCode: 1,
expectedStderr: "Error: connection error: desc = \"transport: error while dialing: dial unix does-not-exist.sock: connect: no such file or directory\"\n",
},
{
name: "show selectors",
args: []string{"-spiffeID", "spiffe://example.org/spire/agent/agent2"},
existentAgents: testAgentsWithSelectors,
expectedReturnCode: 0,
expectedStdout: "Selectors : k8s_psat:agent_ns:spire\nSelectors : k8s_psat:agent_sa:spire-agent\nSelectors : k8s_psat:cluster:demo-cluster",
},
} {
tt := tt
t.Run(tt.name, func(t *testing.T) {
Expand Down
3 changes: 3 additions & 0 deletions cmd/spire-server/cli/agent/show.go
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,9 @@ func (c *showCommand) Run(ctx context.Context, env *common_cli.Env, serverClient
return err
}

for _, s := range agent.Selectors {
env.Printf("Selectors : %s:%s\n", s.Type, s.Value)
}
return nil
}

Expand Down
2 changes: 2 additions & 0 deletions cmd/spire-server/cli/healthcheck/healthcheck.go
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,8 @@ func (c *healthCheckCommand) run() error {
}
return errors.New("cannot create registration client")
}
defer client.Release()

bundleClient := client.NewBundleClient()

// Currently using the ability to fetch a bundle as the health check. This
Expand Down
11 changes: 9 additions & 2 deletions cmd/spire-server/cli/run/run.go
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ var (
Organization: []string{"SPIFFE"},
}

defaultRateLimitAttestation = true
defaultRateLimit = true
)

// Config contains all available configurables, arranged by section
Expand Down Expand Up @@ -155,6 +155,7 @@ type federatesWithBundleEndpointConfig struct {

type rateLimitConfig struct {
Attestation *bool `hcl:"attestation"`
Signing *bool `hcl:"signing"`
UnusedKeys []string `hcl:",unusedKeys"`
}

Expand Down Expand Up @@ -368,11 +369,17 @@ func NewServerConfig(c *Config, logOptions []log.Option, allowUnknownConfig bool
sc.Log = logger

if c.Server.RateLimit.Attestation == nil {
c.Server.RateLimit.Attestation = &defaultRateLimitAttestation
c.Server.RateLimit.Attestation = &defaultRateLimit
}
sc.RateLimit.Attestation = *c.Server.RateLimit.Attestation

if c.Server.RateLimit.Signing == nil {
c.Server.RateLimit.Signing = &defaultRateLimit
}
sc.RateLimit.Signing = *c.Server.RateLimit.Signing

sc.Experimental.AllowAgentlessNodeAttestors = c.Server.Experimental.AllowAgentlessNodeAttestors

if c.Server.Federation != nil {
if c.Server.Federation.BundleEndpoint != nil {
sc.Federation.BundleEndpoint = &bundle.EndpointConfig{
Expand Down
28 changes: 28 additions & 0 deletions cmd/spire-server/cli/run/run_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -835,6 +835,34 @@ func TestNewServerConfig(t *testing.T) {
require.True(t, c.RateLimit.Attestation)
},
},
{
msg: "signing rate limit is on by default",
input: func(c *Config) {
},
test: func(t *testing.T, c *server.Config) {
require.True(t, c.RateLimit.Signing)
},
},
{
msg: "signing rate limit can be explicitly disabled",
input: func(c *Config) {
value := false
c.Server.RateLimit.Signing = &value
},
test: func(t *testing.T, c *server.Config) {
require.False(t, c.RateLimit.Signing)
},
},
{
msg: "signing rate limit can be explicitly enabled",
input: func(c *Config) {
value := true
c.Server.RateLimit.Signing = &value
},
test: func(t *testing.T, c *server.Config) {
require.True(t, c.RateLimit.Signing)
},
},
}

for _, testCase := range cases {
Expand Down
30 changes: 15 additions & 15 deletions conf/agent/agent_full.conf
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
# This is the SPIRE Agent configuration file including all possible configuration
# options.
# options.

# agent: Contains core configuration parameters.
agent {
Expand All @@ -24,16 +24,16 @@ agent {

# server_address: DNS name or IP address of the SPIRE server.
server_address = "127.0.0.1"

# server_port: Port number of the SPIRE server.
server_port = "8081"

# socket_path: Location to bind the workload API socket. Default: /tmp/agent.sock.
socket_path = "/tmp/agent.sock"

# trust_bundle_path: Path to the SPIRE server CA bundle.
trust_bundle_path = "./conf/agent/dummy_root_ca.crt"

# trust_bundle_url: URL to download the initial SPIRE server trust bundle.
# trust_bundle_url = ""

Expand All @@ -56,9 +56,9 @@ agent {
# Each nested object has the following format:
#
# PluginType "plugin_name" {
#
#
# # plugin_cmd: Path to the plugin implementation binary (optional, not
# # needed for built-ins)
# # needed for built-ins)
# plugin_cmd = <string>
#
# # plugin_checksum: An optional sha256 of the plugin binary (optional,
Expand Down Expand Up @@ -149,7 +149,7 @@ plugins {
# cluster: Name of the cluster. It must correspond to a cluster
# configured in the server plugin.
# cluster = ""

# token_path: Path to the service account token on disk.
# Default: /run/secrets/kubernetes.io/serviceaccount/token.
# token_path = "/run/secrets/kubernetes.io/serviceaccount/token"
Expand Down Expand Up @@ -180,7 +180,7 @@ plugins {
# certificate_path: The path to the certificate bundle on disk. The
# file must contain one or more PEM blocks, starting with the identity
# certificate followed by any intermediate certificates necessary for
# chain-of-trust validation.
# chain-of-trust validation.
# certificate_path = ""

# intermediates_path: Optional. The path to a chain of intermediate
Expand All @@ -204,7 +204,7 @@ plugins {
# docker_version = ""
}
}

# WorkloadAttestor "k8s": A workload attestor which allows selectors based
# on Kubernetes constructs such ns (namespace) and sa (service account).
WorkloadAttestor "k8s" {
Expand Down Expand Up @@ -244,7 +244,7 @@ plugins {
# node_name_env = "MY_NODE_NAME"

# node_name: The name of the node. Overrides the value obtained by
# the environment variable specified by node_name_env.
# the environment variable specified by node_name_env.
# node_name = ""
}
}
Expand Down Expand Up @@ -276,7 +276,7 @@ plugins {
# port = 9988
# }

# DogStatsd = [
# DogStatsd = [
# # List of DogStatsd addresses.
# { address = "localhost:8125" },
# { address = "collector.example.org:1337" },
Expand All @@ -301,7 +301,7 @@ plugins {
# }

# health_checks: If health checking is desired use this section to configure
# and expose an additional server endpoint for such purpose.
# and expose an additional agent endpoint for such purpose.
# health_checks {
# # listener_enabled: Enables health checks endpoint.
# listener_enabled = true
Expand All @@ -312,9 +312,9 @@ plugins {
# # bind_port: HTTP Port number of the health checks endpoint. Default: 80.
# # bind_port = "80"

# # live_path: HTTP resource path for checking server liveness. Default: /live.
# # live_path: HTTP resource path for checking agent liveness. Default: /live.
# # live_path = "/live"

# # ready_path: HTTP resource path for checking server readiness. Default: /ready.
# # ready_path: HTTP resource path for checking agent readiness. Default: /ready.
# # ready_path = "/ready"
# }
4 changes: 4 additions & 0 deletions conf/server/server_full.conf
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,10 @@ server {
# # Controls whether or not node attestation is rate limited to one
# # attempt per-second per-IP. Default: true.
# attestation = true

# # Controls whether or not X509 and JWT signing are rate limited to 500
# # requests per-second per-IP (separately). Default: true.
# signing = true
# }

# registration_uds_path: Location to bind the registration API socket.
Expand Down
33 changes: 19 additions & 14 deletions doc/plugin_agent_workloadattestor_k8s.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# Agent plugin: WorkloadAttestor "k8s"

The `k8s` plugin generates kubernetes-based selectors for workloads calling the agent.
The `k8s` plugin generates Kubernetes-based selectors for workloads calling the agent.
It does so by retrieving the workload's pod ID from its cgroup membership, then querying
the kubelet for information about the pod.

Expand All @@ -19,16 +19,17 @@ the kubelet is contacted over 127.0.0.1 (requires host networking to be
enabled). In the latter case, the hostname is used to perform certificate
server name validation against the kubelet certificate.

**Note** kubelet authentication via bearer token requires that the kubelet be
started with the `--authentication-token-webhook` flag. See [Kubelet authentication/authorization](https://kubernetes.io/docs/reference/command-line-tools-reference/kubelet-authentication-authorization/)
for details.
> **Note** kubelet authentication via bearer token requires that the kubelet be
> started with the `--authentication-token-webhook` flag.
> See [Kubelet authentication/authorization](https://kubernetes.io/docs/reference/command-line-tools-reference/kubelet-authentication-authorization/)
> for details.

**Note** The kubelet uses the TokenReview API to validate bearer tokens. This
requires reachability to the Kubernetes API server. Therefore API server downtime can
interrupt workload attestation. The `--authentication-token-webhook-cache-ttl` kubelet flag
controls how long the kubelet caches TokenReview responses and may help to
mitigate this issue. A large cache ttl value is not recommended however, as
that can impact permission revocation.
> **Note** The kubelet uses the TokenReview API to validate bearer tokens.
> This requires reachability to the Kubernetes API server. Therefore API server downtime can
> interrupt workload attestation. The `--authentication-token-webhook-cache-ttl` kubelet flag
> controls how long the kubelet caches TokenReview responses and may help to
> mitigate this issue. A large cache ttl value is not recommended however, as
> that can impact permission revocation.

| Configuration | Description |
| ------------- | ----------- |
Expand All @@ -46,19 +47,23 @@ that can impact permission revocation.
| -------- | ----- |
| k8s:ns | The workload's namespace |
| k8s:sa | The workload's service account |
| k8s:container-image | The image of the workload's container |
| k8s:container-image | The Image OR ImageID of the container in the workload's pod which is requesting an SVID, [as reported by K8S](https://pkg.go.dev/k8s.io/api/core/v1#ContainerStatus). Selector value may be an image tag, such as: `docker.io/envoyproxy/envoy-alpine:v1.16.0`, or a resolved SHA256 image digest, such as `docker.io/envoyproxy/envoy-alpine@sha256:bf862e5f5eca0a73e7e538224578c5cf867ce2be91b5eaed22afc153c00363eb` |
| k8s:container-name | The name of the workload's container |
| k8s:node-name | The name of the workload's node |
| k8s:pod-label | A label given to the the workload's pod |
| k8s:pod-label | A label given to the workload's pod |
| k8s:pod-owner | The name of the workload's pod owner |
| k8s:pod-owner-uid | The UID of the workload's pod owner |
| k8s:pod-uid | The UID of the workload's pod |
| k8s:pod-name | The name of the workload's pod |
| k8s:pod-image | An image of a container in workload's pod |
| k8s:pod-image | An Image OR ImageID of any container in the workload's pod, [as reported by K8S](https://pkg.go.dev/k8s.io/api/core/v1#ContainerStatus). Selector value may be an image tag, such as: `docker.io/envoyproxy/envoy-alpine:v1.16.0`, or a resolved SHA256 image digest, such as `docker.io/envoyproxy/envoy-alpine@sha256:bf862e5f5eca0a73e7e538224578c5cf867ce2be91b5eaed22afc153c00363eb`|
| k8s:pod-image-count | The number of container images in workload's pod |
| k8s:pod-init-image | An image of an init container in workload's pod |
| k8s:pod-init-image | An Image OR ImageID of any init container in the workload's pod, [as reported by K8S](https://pkg.go.dev/k8s.io/api/core/v1#ContainerStatus). Selector value may be an image tag, such as: `docker.io/envoyproxy/envoy-alpine:v1.16.0`, or a resolved SHA256 image digest, such as `docker.io/envoyproxy/envoy-alpine@sha256:bf862e5f5eca0a73e7e538224578c5cf867ce2be91b5eaed22afc153c00363eb`|
| k8s:pod-init-image-count | The number of init container images in workload's pod |

> **Note** `container-image` will ONLY match against the specific container in the pod that is contacting SPIRE on behalf of
> the pod, whereas `pod-image` and `pod-init-image` will match against ANY container or init container in the Pod,
> respectively.

## Examples

To use the kubelet read-only port:
Expand Down
9 changes: 8 additions & 1 deletion doc/plugin_server_nodeattestor_aws_iid.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ this plugin resolves the agent's AWS IID-based SPIFFE ID into a set of selectors
| `access_key_id` | AWS access key id | Value of `AWS_ACCESS_KEY_ID` environment variable |
| `secret_access_key` | AWS secret access key | Value of `AWS_SECRET_ACCESS_KEY` environment variable |
| `skip_block_device` | Skip anti-tampering mechanism which checks to make sure that the underlying root volume has not been detached prior to attestation. | false |
| `disable_instance_profile_selectors` | Disables retrieving the attesting instance profile information that is used in the selectors. Useful in cases where the server cannot reach iam.amazonaws.com | false |

A sample configuration:

Expand All @@ -25,6 +26,12 @@ A sample configuration:
}
}
```

## Disabling Instance Profile Selectors
In cases where spire-server is running in a location with no public internet access available, setting `disable_instance_profile_selectors = true` will prevent the server from making requests to `iam.amazonaws.com`. This is needed as spire-server will fail to attest nodes as it cannot retrieve the metadata information.

When this is enabled, `IAM Role` selector information will no longer be available for use.

## AWS IAM Permissions
The user or role identified by the configured credentials must have permissions for `ec2:DescribeInstances`.

Expand Down Expand Up @@ -58,7 +65,7 @@ This plugin generates the following selectors related to the instance where the

All of the selectors have the type `aws_iid`.

The `IAM role` selector is included in the generated set of selectors only if the instance has an IAM Instance Profile associated.
The `IAM role` selector is included in the generated set of selectors only if the instance has an IAM Instance Profile associated and `disable_instance_profile_selectors = false`

## Security Considerations
The AWS Instance Identity Document, which this attestor leverages to prove node identity, is available to any process running on the node by default. As a result, it is possible for non-agent code running on a node to attest to the SPIRE Server, allowing it to obtain any workload identity that the node is authorized to run.
Expand Down
33 changes: 33 additions & 0 deletions doc/plugin_server_notifier_k8sbundle.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ The plugin accepts the following configuration options:
| config_map | The name of the ConfigMap | `spire-bundle` |
| config_map_key | The key within the ConfigMap for the bundle | `bundle.crt` |
| kube_config_file_path | The path on disk to the kubeconfig containing configuration to enable interaction with the Kubernetes API server. If unset, it is assumed the notifier is in-cluster and in-cluster credentials will be used. | |
| webhook_label | If set, rotate the CA Bundle in validating and mutating webhooks with this label set to `true`. | |

## Configuring Kubernetes

Expand All @@ -22,6 +23,7 @@ The following actions are required to set up the plugin.
- Bind ClusterRole or Role that can `get` and `patch` the ConfigMap to Service Account
- In the case of in-cluster SPIRE server, it is Service Account that runs the SPIRE server
- In the case of out-of-cluster SPIRE server, it is Service Account that interacts with the Kubernetes API server
- In the case of setting `webhook_label`, the ClusterRole additionally needs permissions to `get`, `list`, `patch`, and `watch` `mutatingwebhookconfigurations` and `validatingwebhookconfigurations`.
- Create the ConfigMap that the plugin pushes

For example:
Expand Down Expand Up @@ -62,6 +64,23 @@ metadata:
namespace: spire
```

### Configuration when Rotating Webhook CA Bundles
When rotating webhook CA bundles, use the below ClusterRole:

```yaml
kind: ClusterRole
apiVersion: rbac.authorization.k8s.io/v1
metadata:
name: spire-server-cluster-role
rules:
- apiGroups: [""]
resources: ["configmaps"]
verbs: ["get", "patch"]
- apiGroups: ["admissionregistration.k8s.io"]
resources: ["mutatingwebhookconfigurations", "validatingwebhookconfigurations"]
verbs: ["get", "list", "patch", "watch"]
```

## Sample configurations

### Default In-Cluster
Expand Down Expand Up @@ -92,3 +111,17 @@ the credentials found in the `/path/to/kubeconfig` file.
}
}
```

### Default In-Cluster with Webhook Rotation
The following configuration pushes bundle contents from an in-cluster SPIRE
server to
- The `bundle.crt` key in the `spire:spire-bundle` ConfigMap
- Validating and mutating webhooks with a label of `spiffe.io/webhook: true`

```
Notifier "k8sbundle" {
plugin_data {
webhook_label = "spiffe.io/webhook"
}
}
```
2 changes: 1 addition & 1 deletion doc/spire_agent.md
Original file line number Diff line number Diff line change
Expand Up @@ -109,7 +109,7 @@ The agent can expose additional endpoint that can be used for health checking. I
health_checks {
listener_enabled = true
bind_address = "localhost"
bind_port = "80"
bind_port = "8080"
live_path = "/live"
ready_path = "/ready"
}
Expand Down
Loading