Skip to content

Commit

Permalink
Introduce a configurable SVID rotation threshold
Browse files Browse the repository at this point in the history
Signed-off-by: Tomoya Usami <tousami@zlab.co.jp>
  • Loading branch information
Tomoya Usami committed Dec 14, 2023
1 parent 53192d2 commit ee6ecb9
Show file tree
Hide file tree
Showing 14 changed files with 433 additions and 212 deletions.
14 changes: 14 additions & 0 deletions cmd/spire-agent/cli/run/run.go
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,8 @@ const (

bundleFormatPEM = "pem"
bundleFormatSPIFFE = "spiffe"

minimumAvailabilityTarget = 24 * time.Hour
)

// Config contains all available configurables, arranged by section
Expand Down Expand Up @@ -86,6 +88,7 @@ type agentConfig struct {
TrustDomain string `hcl:"trust_domain"`
AllowUnauthenticatedVerifiers bool `hcl:"allow_unauthenticated_verifiers"`
AllowedForeignJWTClaims []string `hcl:"allowed_foreign_jwt_claims"`
AvailabilityTarget string `hcl:"availability_target"`

AuthorizedDelegates []string `hcl:"authorized_delegates"`

Expand Down Expand Up @@ -564,6 +567,17 @@ func NewAgentConfig(c *Config, logOptions []log.Option, allowUnknownConfig bool)

ac.AuthorizedDelegates = c.Agent.AuthorizedDelegates

if c.Agent.AvailabilityTarget != "" {
t, err := time.ParseDuration(c.Agent.AvailabilityTarget)
if err != nil {
return nil, fmt.Errorf("unable to parse availability_target: %w", err)
}
if t < minimumAvailabilityTarget {
return nil, fmt.Errorf("availability_target must be at least %s", minimumAvailabilityTarget.String())
}
ac.AvailabilityTarget = t
}

if cmp.Diff(experimentalConfig{}, c.Agent.Experimental) != "" {
logger.Warn("Experimental features have been enabled. Please see doc/upgrading.md for upgrade and compatibility considerations for experimental features.")
}
Expand Down
20 changes: 20 additions & 0 deletions cmd/spire-agent/cli/run/run_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import (
"path/filepath"
"strings"
"testing"
"time"

"github.com/hashicorp/hcl/hcl/ast"
"github.com/sirupsen/logrus"
Expand Down Expand Up @@ -974,6 +975,25 @@ func TestNewAgentConfig(t *testing.T) {
assert.NotNil(t, c)
},
},
{
msg: "availability_target parses a duration",
input: func(c *Config) {
c.Agent.AvailabilityTarget = "24h"
},
test: func(t *testing.T, c *agent.Config) {
require.EqualValues(t, 24*time.Hour, c.AvailabilityTarget)
},
},
{
msg: "availability_target is too short",
expectError: true,
input: func(c *Config) {
c.Agent.AvailabilityTarget = "1h"
},
test: func(t *testing.T, c *agent.Config) {
require.Nil(t, c)
},
},
}
cases = append(cases, newAgentConfigCasesOS()...)
for _, testCase := range cases {
Expand Down
64 changes: 37 additions & 27 deletions doc/spire_agent.md
Original file line number Diff line number Diff line change
Expand Up @@ -41,33 +41,34 @@ SPIRE configuration files may be represented in either HCL or JSON. Please see t
If the -expandEnv flag is passed to SPIRE, `$VARIABLE` or `${VARIABLE}` style environment variables are expanded before parsing.
This may be useful for templating configuration files, for example across different trust domains, or for inserting secrets like join tokens.

| Configuration | Description | Default |
|-----------------------------------|--------------------------------------------------------------------------------------------------------------------------------|----------------------------------|
| `admin_socket_path` | Location to bind the admin API socket (disabled as default) | |
| `allow_unauthenticated_verifiers` | Allow agent to release trust bundles to unauthenticated verifiers | false |
| `allowed_foreign_jwt_claims` | List of trusted claims to be returned when validating foreign JWTSVIDs | |
| `authorized_delegates` | A SPIFFE ID list of the authorized delegates. See [Delegated Identity API](#delegated-identity-api) for more information | |
| `data_dir` | A directory the agent can use for its runtime data | $PWD |
| `experimental` | The experimental options that are subject to change or removal (see below) | |
| `insecure_bootstrap` | If true, the agent bootstraps without verifying the server's identity | false |
| `join_token` | An optional token which has been generated by the SPIRE server | |
| `log_file` | File to write logs to | |
| `log_level` | Sets the logging level &lt;DEBUG&vert;INFO&vert;WARN&vert;ERROR&gt; | INFO |
| `log_format` | Format of logs, &lt;text&vert;json&gt; | Text |
| `log_source_location` | If true, logs include source file, line number, and method name fields (adds a bit of runtime cost) | false |
| `profiling_enabled` | If true, enables a [net/http/pprof](https://pkg.go.dev/net/http/pprof) endpoint | false |
| `profiling_freq` | Frequency of dumping profiling data to disk. Only enabled when `profiling_enabled` is `true` and `profiling_freq` > 0. | |
| `profiling_names` | List of profile names that will be dumped to disk on each profiling tick, see [Profiling Names](#profiling-names) | |
| `profiling_port` | Port number of the [net/http/pprof](https://pkg.go.dev/net/http/pprof) endpoint. Only used when `profiling_enabled` is `true`. | |
| `server_address` | DNS name or IP address of the SPIRE server | |
| `server_port` | Port number of the SPIRE server | |
| `socket_path` | Location to bind the SPIRE Agent API socket (Unix only) | /tmp/spire-agent/public/api.sock |
| `sds` | Optional SDS configuration section | |
| `trust_bundle_path` | Path to the SPIRE server CA bundle | |
| `trust_bundle_url` | URL to download the initial SPIRE server trust bundle | |
| `trust_bundle_format` | Format of the initial trust bundle, pem or spiffe | pem |
| `trust_domain` | The trust domain that this agent belongs to (should be no more than 255 characters) | |
| `workload_x509_svid_key_type` | The workload X509 SVID key type &lt;rsa-2048&vert;ec-p256&gt; | ec-p256 |
| Configuration | Description | Default |
|-----------------------------------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|----------------------------------|
| `admin_socket_path` | Location to bind the admin API socket (disabled as default) | |
| `allow_unauthenticated_verifiers` | Allow agent to release trust bundles to unauthenticated verifiers | false |
| `allowed_foreign_jwt_claims` | List of trusted claims to be returned when validating foreign JWTSVIDs | |
| `authorized_delegates` | A SPIFFE ID list of the authorized delegates. See [Delegated Identity API](#delegated-identity-api) for more information | |
| `data_dir` | A directory the agent can use for its runtime data | $PWD |
| `experimental` | The experimental options that are subject to change or removal (see below) | |
| `insecure_bootstrap` | If true, the agent bootstraps without verifying the server's identity | false |
| `join_token` | An optional token which has been generated by the SPIRE server | |
| `log_file` | File to write logs to | |
| `log_level` | Sets the logging level &lt;DEBUG&vert;INFO&vert;WARN&vert;ERROR&gt; | INFO |
| `log_format` | Format of logs, &lt;text&vert;json&gt; | Text |
| `log_source_location` | If true, logs include source file, line number, and method name fields (adds a bit of runtime cost) | false |
| `profiling_enabled` | If true, enables a [net/http/pprof](https://pkg.go.dev/net/http/pprof) endpoint | false |
| `profiling_freq` | Frequency of dumping profiling data to disk. Only enabled when `profiling_enabled` is `true` and `profiling_freq` > 0. | |
| `profiling_names` | List of profile names that will be dumped to disk on each profiling tick, see [Profiling Names](#profiling-names) | |
| `profiling_port` | Port number of the [net/http/pprof](https://pkg.go.dev/net/http/pprof) endpoint. Only used when `profiling_enabled` is `true`. | |
| `server_address` | DNS name or IP address of the SPIRE server | |
| `server_port` | Port number of the SPIRE server | |
| `socket_path` | Location to bind the SPIRE Agent API socket (Unix only) | /tmp/spire-agent/public/api.sock |
| `sds` | Optional SDS configuration section | |
| `trust_bundle_path` | Path to the SPIRE server CA bundle | |
| `trust_bundle_url` | URL to download the initial SPIRE server trust bundle | |
| `trust_bundle_format` | Format of the initial trust bundle, pem or spiffe | pem |
| `trust_domain` | The trust domain that this agent belongs to (should be no more than 255 characters) | |
| `workload_x509_svid_key_type` | The workload X509 SVID key type &lt;rsa-2048&vert;ec-p256&gt; | ec-p256 |
| `availability_target` | The minimum amount of time desired to gracefully handle SPIRE Server or Agent downtime. This configurable influences how aggressively X509 SVIDs should be rotated. If set, must be at least 24h. See [Availability Target](#availability-target) | |

| experimental | Description | Default |
|:------------------|-----------------------------------------------------------------|-------------------------|
Expand Down Expand Up @@ -105,6 +106,15 @@ These are the available profiles that can be set in the `profiling_freq` configu
- `trace`
- `cpu`

### Availability Target

_Note: The `availability_target` only affects the agent SVIDs and workload X509-SVIDs, but not JWT-SVIDs._

If the `availability_target` is set, the agent will rotate an X509 SVID when its remaining lifetime reaches the `availability_target`.

To guarantee the `availability_target`, grace period (`SVID lifetime - availability_target`) must be at least 12h.
If not satisfied, the agent will rotate the SVID by the default rotation strategy (1/2 of lifetime).

## Plugin configuration

The agent configuration file also contains the configuration for the agent plugins.
Expand Down
5 changes: 4 additions & 1 deletion pkg/agent/agent.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ import (
"github.com/spiffe/spire/pkg/common/diskutil"
"github.com/spiffe/spire/pkg/common/health"
"github.com/spiffe/spire/pkg/common/profiling"
"github.com/spiffe/spire/pkg/common/rotationutil"
"github.com/spiffe/spire/pkg/common/telemetry"
"github.com/spiffe/spire/pkg/common/uptime"
"github.com/spiffe/spire/pkg/common/util"
Expand Down Expand Up @@ -211,6 +212,7 @@ func (a *Agent) attest(ctx context.Context, sto storage.Storage, cat catalog.Cat
}

func (a *Agent) newManager(ctx context.Context, sto storage.Storage, cat catalog.Catalog, metrics telemetry.Metrics, as *node_attestor.AttestationResult, cache *storecache.Cache, na nodeattestor.NodeAttestor) (manager.Manager, error) {
log := a.c.Log.WithField(telemetry.SubsystemName, telemetry.Manager)
config := &manager.Config{
SVID: as.SVID,
SVIDKey: as.Key,
Expand All @@ -219,14 +221,15 @@ func (a *Agent) newManager(ctx context.Context, sto storage.Storage, cat catalog
Catalog: cat,
TrustDomain: a.c.TrustDomain,
ServerAddr: a.c.ServerAddress,
Log: a.c.Log.WithField(telemetry.SubsystemName, telemetry.Manager),
Log: log,
Metrics: metrics,
WorkloadKeyType: a.c.WorkloadKeyType,
Storage: sto,
SyncInterval: a.c.SyncInterval,
SVIDCacheMaxSize: a.c.X509SVIDCacheMaxSize,
SVIDStoreCache: cache,
NodeAttestor: na,
RotationStrategy: rotationutil.NewRotationStrategy(a.c.AvailabilityTarget),
}

mgr := manager.New(config)
Expand Down
3 changes: 3 additions & 0 deletions pkg/agent/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,9 @@ type Config struct {
AllowedForeignJWTClaims []string

AuthorizedDelegates []string

// AvailabilityTarget controls how frequently rotate SVIDs
AvailabilityTarget time.Duration
}

func New(c *Config) *Agent {
Expand Down
Loading

0 comments on commit ee6ecb9

Please sign in to comment.