diff --git a/authority/config.go b/authority/config.go index 412f54db..99fdf457 100644 --- a/authority/config.go +++ b/authority/config.go @@ -28,6 +28,7 @@ var ( Renegotiation: false, } defaultDisableRenewal = false + defaultEnableSSHCA = false globalProvisionerClaims = provisioner.Claims{ MinTLSDur: &provisioner.Duration{Duration: 5 * time.Minute}, // TLS certs MaxTLSDur: &provisioner.Duration{Duration: 24 * time.Hour}, @@ -39,6 +40,7 @@ var ( MinHostSSHDur: &provisioner.Duration{Duration: 5 * time.Minute}, // Host SSH certs MaxHostSSHDur: &provisioner.Duration{Duration: 30 * 24 * time.Hour}, DefaultHostSSHDur: &provisioner.Duration{Duration: 30 * 24 * time.Hour}, + EnableSSHCA: &defaultEnableSSHCA, } ) diff --git a/authority/provisioner/aws.go b/authority/provisioner/aws.go index 07285940..dbe33c5c 100644 --- a/authority/provisioner/aws.go +++ b/authority/provisioner/aws.go @@ -275,6 +275,9 @@ func (p *AWS) AuthorizeSign(ctx context.Context, token string) ([]SignOption, er // Check for the sign ssh method, default to sign X.509 if m := MethodFromContext(ctx); m == SignSSHMethod { + if p.claimer.IsSSHCAEnabled() == false { + return nil, errors.Errorf("ssh ca is disabled for provisioner %s", p.GetID()) + } return p.authorizeSSHSign(payload) } diff --git a/authority/provisioner/azure.go b/authority/provisioner/azure.go index d84e9f91..6b298133 100644 --- a/authority/provisioner/azure.go +++ b/authority/provisioner/azure.go @@ -267,6 +267,9 @@ func (p *Azure) AuthorizeSign(ctx context.Context, token string) ([]SignOption, // Check for the sign ssh method, default to sign X.509 if m := MethodFromContext(ctx); m == SignSSHMethod { + if p.claimer.IsSSHCAEnabled() == false { + return nil, errors.Errorf("ssh ca is disabled for provisioner %s", p.GetID()) + } return p.authorizeSSHSign(claims, name) } diff --git a/authority/provisioner/claims.go b/authority/provisioner/claims.go index 23c85002..4eba5ad7 100644 --- a/authority/provisioner/claims.go +++ b/authority/provisioner/claims.go @@ -20,6 +20,7 @@ type Claims struct { MinHostSSHDur *Duration `json:"minHostSSHCertDuration,omitempty"` MaxHostSSHDur *Duration `json:"maxHostSSHCertDuration,omitempty"` DefaultHostSSHDur *Duration `json:"defaultHostSSHCertDuration,omitempty"` + EnableSSHCA *bool `json:"enableSSHCA,omitempty"` } // Claimer is the type that controls claims. It provides an interface around the @@ -38,6 +39,7 @@ func NewClaimer(claims *Claims, global Claims) (*Claimer, error) { // Claims returns the merge of the inner and global claims. func (c *Claimer) Claims() Claims { disableRenewal := c.IsDisableRenewal() + enableSSHCA := c.IsSSHCAEnabled() return Claims{ MinTLSDur: &Duration{c.MinTLSCertDuration()}, MaxTLSDur: &Duration{c.MaxTLSCertDuration()}, @@ -49,6 +51,7 @@ func (c *Claimer) Claims() Claims { MinHostSSHDur: &Duration{c.MinHostSSHCertDuration()}, MaxHostSSHDur: &Duration{c.MaxHostSSHCertDuration()}, DefaultHostSSHDur: &Duration{c.DefaultHostSSHCertDuration()}, + EnableSSHCA: &enableSSHCA, } } @@ -152,6 +155,16 @@ func (c *Claimer) MaxHostSSHCertDuration() time.Duration { return c.claims.MaxHostSSHDur.Duration } +// IsSSHCAEnabled returns if the SSH CA is enabled for the provisioner. If the +// property is not set within the provisioner, then the global value from the +// authority configuration will be used. +func (c *Claimer) IsSSHCAEnabled() bool { + if c.claims == nil || c.claims.EnableSSHCA == nil { + return *c.global.EnableSSHCA + } + return *c.claims.EnableSSHCA +} + // Validate validates and modifies the Claims with default values. func (c *Claimer) Validate() error { var ( diff --git a/authority/provisioner/gcp.go b/authority/provisioner/gcp.go index d5dde616..0604c572 100644 --- a/authority/provisioner/gcp.go +++ b/authority/provisioner/gcp.go @@ -214,6 +214,9 @@ func (p *GCP) AuthorizeSign(ctx context.Context, token string) ([]SignOption, er // Check for the sign ssh method, default to sign X.509 if m := MethodFromContext(ctx); m == SignSSHMethod { + if p.claimer.IsSSHCAEnabled() == false { + return nil, errors.Errorf("ssh ca is disabled for provisioner %s", p.GetID()) + } return p.authorizeSSHSign(claims) } diff --git a/authority/provisioner/jwk.go b/authority/provisioner/jwk.go index 012e08a9..5ecf4d6e 100644 --- a/authority/provisioner/jwk.go +++ b/authority/provisioner/jwk.go @@ -143,6 +143,9 @@ func (p *JWK) AuthorizeSign(ctx context.Context, token string) ([]SignOption, er // Check for SSH token if claims.Step != nil && claims.Step.SSH != nil { + if p.claimer.IsSSHCAEnabled() == false { + return nil, errors.Errorf("ssh ca is disabled for provisioner %s", p.GetID()) + } return p.authorizeSSHSign(claims) } diff --git a/authority/provisioner/oidc.go b/authority/provisioner/oidc.go index 0c0f840e..a71d2c1b 100644 --- a/authority/provisioner/oidc.go +++ b/authority/provisioner/oidc.go @@ -268,6 +268,9 @@ func (o *OIDC) AuthorizeSign(ctx context.Context, token string) ([]SignOption, e // Check for the sign ssh method, default to sign X.509 if m := MethodFromContext(ctx); m == SignSSHMethod { + if o.claimer.IsSSHCAEnabled() == false { + return nil, errors.Errorf("ssh ca is disabled for provisioner %s", o.GetID()) + } return o.authorizeSSHSign(claims) }