Contain policy engines inside provisioner Controller

This commit is contained in:
Herman Slatman 2022-04-22 01:20:38 +02:00
parent ef110a94df
commit c40a4d2694
No known key found for this signature in database
GPG key ID: F4D8A44EA0A75A4F
16 changed files with 232 additions and 228 deletions

View file

@ -7,6 +7,7 @@ import (
"go.step.sm/linkedca" "go.step.sm/linkedca"
"github.com/smallstep/certificates/authority/admin"
authPolicy "github.com/smallstep/certificates/authority/policy" authPolicy "github.com/smallstep/certificates/authority/policy"
policy "github.com/smallstep/certificates/policy" policy "github.com/smallstep/certificates/policy"
) )
@ -228,7 +229,10 @@ func (a *Authority) reloadPolicyEngines(ctx context.Context) error {
linkedPolicy, err := a.adminDB.GetAuthorityPolicy(ctx) linkedPolicy, err := a.adminDB.GetAuthorityPolicy(ctx)
if err != nil { if err != nil {
return fmt.Errorf("error getting policy to (re)load policy engines: %w", err) var ae *admin.Error
if isAdminError := errors.As(err, &ae); (isAdminError && ae.Type != admin.ErrorNotFoundType.String()) || !isAdminError {
return fmt.Errorf("error getting policy to (re)load policy engines: %w", err)
}
} }
policyOptions = policyToCertificates(linkedPolicy) policyOptions = policyToCertificates(linkedPolicy)
} else { } else {

View file

@ -8,8 +8,6 @@ import (
"time" "time"
"github.com/pkg/errors" "github.com/pkg/errors"
"github.com/smallstep/certificates/authority/policy"
) )
// ACME is the acme provisioner type, an entity that can authorize the ACME // ACME is the acme provisioner type, an entity that can authorize the ACME
@ -28,8 +26,7 @@ type ACME struct {
Claims *Claims `json:"claims,omitempty"` Claims *Claims `json:"claims,omitempty"`
Options *Options `json:"options,omitempty"` Options *Options `json:"options,omitempty"`
ctl *Controller ctl *Controller
x509Policy policy.X509Policy
} }
// GetID returns the provisioner unique identifier. // GetID returns the provisioner unique identifier.
@ -86,12 +83,7 @@ func (p *ACME) Init(config Config) (err error) {
return errors.New("provisioner name cannot be empty") return errors.New("provisioner name cannot be empty")
} }
// Initialize the x509 allow/deny policy engine p.ctl, err = NewController(p, p.Claims, config, p.Options)
if p.x509Policy, err = policy.NewX509PolicyEngine(p.Options.GetX509Options()); err != nil {
return err
}
p.ctl, err = NewController(p, p.Claims, config)
return return
} }
@ -115,8 +107,10 @@ type ACMEIdentifier struct {
// certificate for an ACME Order Identifier. // certificate for an ACME Order Identifier.
func (p *ACME) AuthorizeOrderIdentifier(ctx context.Context, identifier ACMEIdentifier) error { func (p *ACME) AuthorizeOrderIdentifier(ctx context.Context, identifier ACMEIdentifier) error {
x509Policy := p.ctl.GetPolicy().GetX509()
// identifier is allowed if no policy is configured // identifier is allowed if no policy is configured
if p.x509Policy == nil { if x509Policy == nil {
return nil return nil
} }
@ -124,9 +118,9 @@ func (p *ACME) AuthorizeOrderIdentifier(ctx context.Context, identifier ACMEIden
var err error var err error
switch identifier.Type { switch identifier.Type {
case IP: case IP:
_, err = p.x509Policy.IsIPAllowed(net.ParseIP(identifier.Value)) _, err = x509Policy.IsIPAllowed(net.ParseIP(identifier.Value))
case DNS: case DNS:
_, err = p.x509Policy.IsDNSAllowed(identifier.Value) _, err = x509Policy.IsDNSAllowed(identifier.Value)
default: default:
err = fmt.Errorf("invalid ACME identifier type '%s' provided", identifier.Type) err = fmt.Errorf("invalid ACME identifier type '%s' provided", identifier.Type)
} }
@ -147,7 +141,7 @@ func (p *ACME) AuthorizeSign(ctx context.Context, token string) ([]SignOption, e
// validators // validators
defaultPublicKeyValidator{}, defaultPublicKeyValidator{},
newValidityValidator(p.ctl.Claimer.MinTLSCertDuration(), p.ctl.Claimer.MaxTLSCertDuration()), newValidityValidator(p.ctl.Claimer.MinTLSCertDuration(), p.ctl.Claimer.MaxTLSCertDuration()),
newX509NamePolicyValidator(p.x509Policy), newX509NamePolicyValidator(p.ctl.GetPolicy().GetX509()),
} }
return opts, nil return opts, nil

View file

@ -17,11 +17,12 @@ import (
"time" "time"
"github.com/pkg/errors" "github.com/pkg/errors"
"github.com/smallstep/certificates/authority/policy"
"github.com/smallstep/certificates/errs"
"go.step.sm/crypto/jose" "go.step.sm/crypto/jose"
"go.step.sm/crypto/sshutil" "go.step.sm/crypto/sshutil"
"go.step.sm/crypto/x509util" "go.step.sm/crypto/x509util"
"github.com/smallstep/certificates/errs"
) )
// awsIssuer is the string used as issuer in the generated tokens. // awsIssuer is the string used as issuer in the generated tokens.
@ -267,8 +268,6 @@ type AWS struct {
Options *Options `json:"options,omitempty"` Options *Options `json:"options,omitempty"`
config *awsConfig config *awsConfig
ctl *Controller ctl *Controller
x509Policy policy.X509Policy
sshHostPolicy policy.HostPolicy
} }
// GetID returns the provisioner unique identifier. // GetID returns the provisioner unique identifier.
@ -423,18 +422,8 @@ func (p *AWS) Init(config Config) (err error) {
} }
} }
// Initialize the x509 allow/deny policy engine
if p.x509Policy, err = policy.NewX509PolicyEngine(p.Options.GetX509Options()); err != nil {
return err
}
// Initialize the SSH allow/deny policy engine for host certificates
if p.sshHostPolicy, err = policy.NewSSHHostPolicyEngine(p.Options.GetSSHOptions()); err != nil {
return err
}
config.Audiences = config.Audiences.WithFragment(p.GetIDForToken()) config.Audiences = config.Audiences.WithFragment(p.GetIDForToken())
p.ctl, err = NewController(p, p.Claims, config) p.ctl, err = NewController(p, p.Claims, config, p.Options)
return return
} }
@ -489,7 +478,7 @@ func (p *AWS) AuthorizeSign(ctx context.Context, token string) ([]SignOption, er
defaultPublicKeyValidator{}, defaultPublicKeyValidator{},
commonNameValidator(payload.Claims.Subject), commonNameValidator(payload.Claims.Subject),
newValidityValidator(p.ctl.Claimer.MinTLSCertDuration(), p.ctl.Claimer.MaxTLSCertDuration()), newValidityValidator(p.ctl.Claimer.MinTLSCertDuration(), p.ctl.Claimer.MaxTLSCertDuration()),
newX509NamePolicyValidator(p.x509Policy), newX509NamePolicyValidator(p.ctl.GetPolicy().GetX509()),
), nil ), nil
} }
@ -769,6 +758,6 @@ func (p *AWS) AuthorizeSSHSign(ctx context.Context, token string) ([]SignOption,
// Require all the fields in the SSH certificate // Require all the fields in the SSH certificate
&sshCertDefaultValidator{}, &sshCertDefaultValidator{},
// Ensure that all principal names are allowed // Ensure that all principal names are allowed
newSSHNamePolicyValidator(p.sshHostPolicy, nil), newSSHNamePolicyValidator(p.ctl.GetPolicy().GetSSHHost(), nil),
), nil ), nil
} }

View file

@ -18,7 +18,6 @@ import (
"go.step.sm/crypto/sshutil" "go.step.sm/crypto/sshutil"
"go.step.sm/crypto/x509util" "go.step.sm/crypto/x509util"
"github.com/smallstep/certificates/authority/policy"
"github.com/smallstep/certificates/errs" "github.com/smallstep/certificates/errs"
) )
@ -103,8 +102,6 @@ type Azure struct {
oidcConfig openIDConfiguration oidcConfig openIDConfiguration
keyStore *keyStore keyStore *keyStore
ctl *Controller ctl *Controller
x509Policy policy.X509Policy
sshHostPolicy policy.HostPolicy
} }
// GetID returns the provisioner unique identifier. // GetID returns the provisioner unique identifier.
@ -224,17 +221,7 @@ func (p *Azure) Init(config Config) (err error) {
return return
} }
// Initialize the x509 allow/deny policy engine p.ctl, err = NewController(p, p.Claims, config, p.Options)
if p.x509Policy, err = policy.NewX509PolicyEngine(p.Options.GetX509Options()); err != nil {
return err
}
// Initialize the SSH allow/deny policy engine for host certificates
if p.sshHostPolicy, err = policy.NewSSHHostPolicyEngine(p.Options.GetSSHOptions()); err != nil {
return err
}
p.ctl, err = NewController(p, p.Claims, config)
return return
} }
@ -375,7 +362,7 @@ func (p *Azure) AuthorizeSign(ctx context.Context, token string) ([]SignOption,
// validators // validators
defaultPublicKeyValidator{}, defaultPublicKeyValidator{},
newValidityValidator(p.ctl.Claimer.MinTLSCertDuration(), p.ctl.Claimer.MaxTLSCertDuration()), newValidityValidator(p.ctl.Claimer.MinTLSCertDuration(), p.ctl.Claimer.MaxTLSCertDuration()),
newX509NamePolicyValidator(p.x509Policy), newX509NamePolicyValidator(p.ctl.GetPolicy().GetX509()),
), nil ), nil
} }
@ -442,7 +429,7 @@ func (p *Azure) AuthorizeSSHSign(ctx context.Context, token string) ([]SignOptio
// Require all the fields in the SSH certificate // Require all the fields in the SSH certificate
&sshCertDefaultValidator{}, &sshCertDefaultValidator{},
// Ensure that all principal names are allowed // Ensure that all principal names are allowed
newSSHNamePolicyValidator(p.sshHostPolicy, nil), newSSHNamePolicyValidator(p.ctl.GetPolicy().GetSSHHost(), nil),
), nil ), nil
} }

View file

@ -21,14 +21,19 @@ type Controller struct {
IdentityFunc GetIdentityFunc IdentityFunc GetIdentityFunc
AuthorizeRenewFunc AuthorizeRenewFunc AuthorizeRenewFunc AuthorizeRenewFunc
AuthorizeSSHRenewFunc AuthorizeSSHRenewFunc AuthorizeSSHRenewFunc AuthorizeSSHRenewFunc
policy *policyEngine
} }
// NewController initializes a new provisioner controller. // NewController initializes a new provisioner controller.
func NewController(p Interface, claims *Claims, config Config) (*Controller, error) { func NewController(p Interface, claims *Claims, config Config, options *Options) (*Controller, error) {
claimer, err := NewClaimer(claims, config.Claims) claimer, err := NewClaimer(claims, config.Claims)
if err != nil { if err != nil {
return nil, err return nil, err
} }
policy, err := newPolicyEngine(options)
if err != nil {
return nil, err
}
return &Controller{ return &Controller{
Interface: p, Interface: p,
Audiences: &config.Audiences, Audiences: &config.Audiences,
@ -36,6 +41,7 @@ func NewController(p Interface, claims *Claims, config Config) (*Controller, err
IdentityFunc: config.GetIdentityFunc, IdentityFunc: config.GetIdentityFunc,
AuthorizeRenewFunc: config.AuthorizeRenewFunc, AuthorizeRenewFunc: config.AuthorizeRenewFunc,
AuthorizeSSHRenewFunc: config.AuthorizeSSHRenewFunc, AuthorizeSSHRenewFunc: config.AuthorizeSSHRenewFunc,
policy: policy,
}, nil }, nil
} }
@ -192,3 +198,10 @@ func SanitizeSSHUserPrincipal(email string) string {
} }
}, strings.ToLower(email)) }, strings.ToLower(email))
} }
func (c *Controller) GetPolicy() *policyEngine {
if c == nil {
return nil
}
return c.policy
}

View file

@ -9,6 +9,8 @@ import (
"time" "time"
"golang.org/x/crypto/ssh" "golang.org/x/crypto/ssh"
"github.com/smallstep/certificates/authority/policy"
) )
var trueValue = true var trueValue = true
@ -30,11 +32,40 @@ func mustDuration(t *testing.T, s string) *Duration {
return d return d
} }
func mustNewPolicyEngine(t *testing.T, options *Options) *policyEngine {
t.Helper()
c, err := newPolicyEngine(options)
if err != nil {
t.Fatal(err)
}
return c
}
func TestNewController(t *testing.T) { func TestNewController(t *testing.T) {
options := &Options{
X509: &X509Options{
AllowedNames: &policy.X509NameOptions{
DNSDomains: []string{"*.local"},
},
},
SSH: &SSHOptions{
Host: &policy.SSHHostCertificateOptions{
AllowedNames: &policy.SSHNameOptions{
DNSDomains: []string{"*.local"},
},
},
User: &policy.SSHUserCertificateOptions{
AllowedNames: &policy.SSHNameOptions{
EmailAddresses: []string{"@example.com"},
},
},
},
}
type args struct { type args struct {
p Interface p Interface
claims *Claims claims *Claims
config Config config Config
options *Options
} }
tests := []struct { tests := []struct {
name string name string
@ -45,7 +76,7 @@ func TestNewController(t *testing.T) {
{"ok", args{&JWK{}, nil, Config{ {"ok", args{&JWK{}, nil, Config{
Claims: globalProvisionerClaims, Claims: globalProvisionerClaims,
Audiences: testAudiences, Audiences: testAudiences,
}}, &Controller{ }, nil}, &Controller{
Interface: &JWK{}, Interface: &JWK{},
Audiences: &testAudiences, Audiences: &testAudiences,
Claimer: mustClaimer(t, nil, globalProvisionerClaims), Claimer: mustClaimer(t, nil, globalProvisionerClaims),
@ -55,24 +86,49 @@ func TestNewController(t *testing.T) {
}, Config{ }, Config{
Claims: globalProvisionerClaims, Claims: globalProvisionerClaims,
Audiences: testAudiences, Audiences: testAudiences,
}}, &Controller{ }, nil}, &Controller{
Interface: &JWK{}, Interface: &JWK{},
Audiences: &testAudiences, Audiences: &testAudiences,
Claimer: mustClaimer(t, &Claims{ Claimer: mustClaimer(t, &Claims{
DisableRenewal: &defaultDisableRenewal, DisableRenewal: &defaultDisableRenewal,
}, globalProvisionerClaims), }, globalProvisionerClaims),
}, false}, }, false},
{"ok with claims and options", args{&JWK{}, &Claims{
DisableRenewal: &defaultDisableRenewal,
}, Config{
Claims: globalProvisionerClaims,
Audiences: testAudiences,
}, options}, &Controller{
Interface: &JWK{},
Audiences: &testAudiences,
Claimer: mustClaimer(t, &Claims{
DisableRenewal: &defaultDisableRenewal,
}, globalProvisionerClaims),
policy: mustNewPolicyEngine(t, options),
}, false},
{"fail claimer", args{&JWK{}, &Claims{ {"fail claimer", args{&JWK{}, &Claims{
MinTLSDur: mustDuration(t, "24h"), MinTLSDur: mustDuration(t, "24h"),
MaxTLSDur: mustDuration(t, "2h"), MaxTLSDur: mustDuration(t, "2h"),
}, Config{ }, Config{
Claims: globalProvisionerClaims, Claims: globalProvisionerClaims,
Audiences: testAudiences, Audiences: testAudiences,
}, nil}, nil, true},
{"fail options", args{&JWK{}, &Claims{
DisableRenewal: &defaultDisableRenewal,
}, Config{
Claims: globalProvisionerClaims,
Audiences: testAudiences,
}, &Options{
X509: &X509Options{
AllowedNames: &policy.X509NameOptions{
DNSDomains: []string{"**.local"},
},
},
}}, nil, true}, }}, nil, true},
} }
for _, tt := range tests { for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) { t.Run(tt.name, func(t *testing.T) {
got, err := NewController(tt.args.p, tt.args.claims, tt.args.config) got, err := NewController(tt.args.p, tt.args.claims, tt.args.config, tt.args.options)
if (err != nil) != tt.wantErr { if (err != nil) != tt.wantErr {
t.Errorf("NewController() error = %v, wantErr %v", err, tt.wantErr) t.Errorf("NewController() error = %v, wantErr %v", err, tt.wantErr)
return return

View file

@ -14,11 +14,12 @@ import (
"time" "time"
"github.com/pkg/errors" "github.com/pkg/errors"
"github.com/smallstep/certificates/authority/policy"
"github.com/smallstep/certificates/errs"
"go.step.sm/crypto/jose" "go.step.sm/crypto/jose"
"go.step.sm/crypto/sshutil" "go.step.sm/crypto/sshutil"
"go.step.sm/crypto/x509util" "go.step.sm/crypto/x509util"
"github.com/smallstep/certificates/errs"
) )
// gcpCertsURL is the url that serves Google OAuth2 public keys. // gcpCertsURL is the url that serves Google OAuth2 public keys.
@ -92,8 +93,6 @@ type GCP struct {
config *gcpConfig config *gcpConfig
keyStore *keyStore keyStore *keyStore
ctl *Controller ctl *Controller
x509Policy policy.X509Policy
sshHostPolicy policy.HostPolicy
} }
// GetID returns the provisioner unique identifier. The name should uniquely // GetID returns the provisioner unique identifier. The name should uniquely
@ -214,18 +213,8 @@ func (p *GCP) Init(config Config) (err error) {
return return
} }
// Initialize the x509 allow/deny policy engine
if p.x509Policy, err = policy.NewX509PolicyEngine(p.Options.GetX509Options()); err != nil {
return err
}
// Initialize the SSH allow/deny policy engine for host certificates
if p.sshHostPolicy, err = policy.NewSSHHostPolicyEngine(p.Options.GetSSHOptions()); err != nil {
return err
}
config.Audiences = config.Audiences.WithFragment(p.GetIDForToken()) config.Audiences = config.Audiences.WithFragment(p.GetIDForToken())
p.ctl, err = NewController(p, p.Claims, config) p.ctl, err = NewController(p, p.Claims, config, p.Options)
return return
} }
@ -283,7 +272,7 @@ func (p *GCP) AuthorizeSign(ctx context.Context, token string) ([]SignOption, er
// validators // validators
defaultPublicKeyValidator{}, defaultPublicKeyValidator{},
newValidityValidator(p.ctl.Claimer.MinTLSCertDuration(), p.ctl.Claimer.MaxTLSCertDuration()), newValidityValidator(p.ctl.Claimer.MinTLSCertDuration(), p.ctl.Claimer.MaxTLSCertDuration()),
newX509NamePolicyValidator(p.x509Policy), newX509NamePolicyValidator(p.ctl.GetPolicy().GetX509()),
), nil ), nil
} }
@ -447,6 +436,6 @@ func (p *GCP) AuthorizeSSHSign(ctx context.Context, token string) ([]SignOption,
// Require all the fields in the SSH certificate // Require all the fields in the SSH certificate
&sshCertDefaultValidator{}, &sshCertDefaultValidator{},
// Ensure that all principal names are allowed // Ensure that all principal names are allowed
newSSHNamePolicyValidator(p.sshHostPolicy, nil), newSSHNamePolicyValidator(p.ctl.GetPolicy().GetSSHHost(), nil),
), nil ), nil
} }

View file

@ -12,7 +12,6 @@ import (
"go.step.sm/crypto/sshutil" "go.step.sm/crypto/sshutil"
"go.step.sm/crypto/x509util" "go.step.sm/crypto/x509util"
"github.com/smallstep/certificates/authority/policy"
"github.com/smallstep/certificates/errs" "github.com/smallstep/certificates/errs"
) )
@ -31,17 +30,14 @@ type stepPayload struct {
// signature requests. // signature requests.
type JWK struct { type JWK struct {
*base *base
ID string `json:"-"` ID string `json:"-"`
Type string `json:"type"` Type string `json:"type"`
Name string `json:"name"` Name string `json:"name"`
Key *jose.JSONWebKey `json:"key"` Key *jose.JSONWebKey `json:"key"`
EncryptedKey string `json:"encryptedKey,omitempty"` EncryptedKey string `json:"encryptedKey,omitempty"`
Claims *Claims `json:"claims,omitempty"` Claims *Claims `json:"claims,omitempty"`
Options *Options `json:"options,omitempty"` Options *Options `json:"options,omitempty"`
ctl *Controller ctl *Controller
x509Policy policy.X509Policy
sshHostPolicy policy.HostPolicy
sshUserPolicy policy.UserPolicy
} }
// GetID returns the provisioner unique identifier. The name and credential id // GetID returns the provisioner unique identifier. The name and credential id
@ -103,22 +99,7 @@ func (p *JWK) Init(config Config) (err error) {
return errors.New("provisioner key cannot be empty") return errors.New("provisioner key cannot be empty")
} }
// Initialize the x509 allow/deny policy engine p.ctl, err = NewController(p, p.Claims, config, p.Options)
if p.x509Policy, err = policy.NewX509PolicyEngine(p.Options.GetX509Options()); err != nil {
return err
}
// Initialize the SSH allow/deny policy engine for user certificates
if p.sshUserPolicy, err = policy.NewSSHUserPolicyEngine(p.Options.GetSSHOptions()); err != nil {
return err
}
// Initialize the SSH allow/deny policy engine for host certificates
if p.sshHostPolicy, err = policy.NewSSHHostPolicyEngine(p.Options.GetSSHOptions()); err != nil {
return err
}
p.ctl, err = NewController(p, p.Claims, config)
return return
} }
@ -202,7 +183,7 @@ func (p *JWK) AuthorizeSign(ctx context.Context, token string) ([]SignOption, er
defaultPublicKeyValidator{}, defaultPublicKeyValidator{},
defaultSANsValidator(claims.SANs), defaultSANsValidator(claims.SANs),
newValidityValidator(p.ctl.Claimer.MinTLSCertDuration(), p.ctl.Claimer.MaxTLSCertDuration()), newValidityValidator(p.ctl.Claimer.MinTLSCertDuration(), p.ctl.Claimer.MaxTLSCertDuration()),
newX509NamePolicyValidator(p.x509Policy), newX509NamePolicyValidator(p.ctl.GetPolicy().GetX509()),
}, nil }, nil
} }
@ -285,7 +266,7 @@ func (p *JWK) AuthorizeSSHSign(ctx context.Context, token string) ([]SignOption,
// Require and validate all the default fields in the SSH certificate. // Require and validate all the default fields in the SSH certificate.
&sshCertDefaultValidator{}, &sshCertDefaultValidator{},
// Ensure that all principal names are allowed // Ensure that all principal names are allowed
newSSHNamePolicyValidator(p.sshHostPolicy, p.sshUserPolicy), newSSHNamePolicyValidator(p.ctl.GetPolicy().GetSSHHost(), p.ctl.GetPolicy().GetSSHUser()),
), nil ), nil
} }

View file

@ -16,7 +16,6 @@ import (
"go.step.sm/crypto/sshutil" "go.step.sm/crypto/sshutil"
"go.step.sm/crypto/x509util" "go.step.sm/crypto/x509util"
"github.com/smallstep/certificates/authority/policy"
"github.com/smallstep/certificates/errs" "github.com/smallstep/certificates/errs"
) )
@ -52,11 +51,8 @@ type K8sSA struct {
Claims *Claims `json:"claims,omitempty"` Claims *Claims `json:"claims,omitempty"`
Options *Options `json:"options,omitempty"` Options *Options `json:"options,omitempty"`
//kauthn kauthn.AuthenticationV1Interface //kauthn kauthn.AuthenticationV1Interface
pubKeys []interface{} pubKeys []interface{}
ctl *Controller ctl *Controller
x509Policy policy.X509Policy
sshHostPolicy policy.HostPolicy
sshUserPolicy policy.UserPolicy
} }
// GetID returns the provisioner unique identifier. The name and credential id // GetID returns the provisioner unique identifier. The name and credential id
@ -144,22 +140,7 @@ func (p *K8sSA) Init(config Config) (err error) {
p.kauthn = k8s.AuthenticationV1() p.kauthn = k8s.AuthenticationV1()
*/ */
// Initialize the x509 allow/deny policy engine p.ctl, err = NewController(p, p.Claims, config, p.Options)
if p.x509Policy, err = policy.NewX509PolicyEngine(p.Options.GetX509Options()); err != nil {
return err
}
// Initialize the SSH allow/deny policy engine for user certificates
if p.sshUserPolicy, err = policy.NewSSHUserPolicyEngine(p.Options.GetSSHOptions()); err != nil {
return err
}
// Initialize the SSH allow/deny policy engine for host certificates
if p.sshHostPolicy, err = policy.NewSSHHostPolicyEngine(p.Options.GetSSHOptions()); err != nil {
return err
}
p.ctl, err = NewController(p, p.Claims, config)
return return
} }
@ -261,7 +242,7 @@ func (p *K8sSA) AuthorizeSign(ctx context.Context, token string) ([]SignOption,
// validators // validators
defaultPublicKeyValidator{}, defaultPublicKeyValidator{},
newValidityValidator(p.ctl.Claimer.MinTLSCertDuration(), p.ctl.Claimer.MaxTLSCertDuration()), newValidityValidator(p.ctl.Claimer.MinTLSCertDuration(), p.ctl.Claimer.MaxTLSCertDuration()),
newX509NamePolicyValidator(p.x509Policy), newX509NamePolicyValidator(p.ctl.GetPolicy().GetX509()),
}, nil }, nil
} }
@ -305,7 +286,7 @@ func (p *K8sSA) AuthorizeSSHSign(ctx context.Context, token string) ([]SignOptio
// Require and validate all the default fields in the SSH certificate. // Require and validate all the default fields in the SSH certificate.
&sshCertDefaultValidator{}, &sshCertDefaultValidator{},
// Ensure that all principal names are allowed // Ensure that all principal names are allowed
newSSHNamePolicyValidator(p.sshHostPolicy, p.sshUserPolicy), newSSHNamePolicyValidator(p.ctl.GetPolicy().GetSSHHost(), p.ctl.GetPolicy().GetSSHUser()),
), nil ), nil
} }

View file

@ -10,13 +10,14 @@ import (
"github.com/pkg/errors" "github.com/pkg/errors"
nebula "github.com/slackhq/nebula/cert" nebula "github.com/slackhq/nebula/cert"
"github.com/smallstep/certificates/authority/policy"
"github.com/smallstep/certificates/errs"
"go.step.sm/crypto/jose" "go.step.sm/crypto/jose"
"go.step.sm/crypto/sshutil" "go.step.sm/crypto/sshutil"
"go.step.sm/crypto/x25519" "go.step.sm/crypto/x25519"
"go.step.sm/crypto/x509util" "go.step.sm/crypto/x509util"
"golang.org/x/crypto/ssh" "golang.org/x/crypto/ssh"
"github.com/smallstep/certificates/errs"
) )
const ( const (
@ -35,16 +36,14 @@ const (
// https://signal.org/docs/specifications/xeddsa/#xeddsa and implemented by // https://signal.org/docs/specifications/xeddsa/#xeddsa and implemented by
// go.step.sm/crypto/x25519. // go.step.sm/crypto/x25519.
type Nebula struct { type Nebula struct {
ID string `json:"-"` ID string `json:"-"`
Type string `json:"type"` Type string `json:"type"`
Name string `json:"name"` Name string `json:"name"`
Roots []byte `json:"roots"` Roots []byte `json:"roots"`
Claims *Claims `json:"claims,omitempty"` Claims *Claims `json:"claims,omitempty"`
Options *Options `json:"options,omitempty"` Options *Options `json:"options,omitempty"`
caPool *nebula.NebulaCAPool caPool *nebula.NebulaCAPool
ctl *Controller ctl *Controller
x509Policy policy.X509Policy
sshHostPolicy policy.HostPolicy
} }
// Init verifies and initializes the Nebula provisioner. // Init verifies and initializes the Nebula provisioner.
@ -63,18 +62,8 @@ func (p *Nebula) Init(config Config) (err error) {
return errs.InternalServer("failed to create ca pool: %v", err) return errs.InternalServer("failed to create ca pool: %v", err)
} }
// Initialize the x509 allow/deny policy engine
if p.x509Policy, err = policy.NewX509PolicyEngine(p.Options.GetX509Options()); err != nil {
return err
}
// Initialize the SSH allow/deny policy engine for host certificates
if p.sshHostPolicy, err = policy.NewSSHHostPolicyEngine(p.Options.GetSSHOptions()); err != nil {
return err
}
config.Audiences = config.Audiences.WithFragment(p.GetIDForToken()) config.Audiences = config.Audiences.WithFragment(p.GetIDForToken())
p.ctl, err = NewController(p, p.Claims, config) p.ctl, err = NewController(p, p.Claims, config, p.Options)
return return
} }
@ -174,7 +163,7 @@ func (p *Nebula) AuthorizeSign(ctx context.Context, token string) ([]SignOption,
}, },
defaultPublicKeyValidator{}, defaultPublicKeyValidator{},
newValidityValidator(p.ctl.Claimer.MinTLSCertDuration(), p.ctl.Claimer.MaxTLSCertDuration()), newValidityValidator(p.ctl.Claimer.MinTLSCertDuration(), p.ctl.Claimer.MaxTLSCertDuration()),
newX509NamePolicyValidator(p.x509Policy), newX509NamePolicyValidator(p.ctl.GetPolicy().GetX509()),
}, nil }, nil
} }
@ -271,7 +260,7 @@ func (p *Nebula) AuthorizeSSHSign(ctx context.Context, token string) ([]SignOpti
// Require all the fields in the SSH certificate // Require all the fields in the SSH certificate
&sshCertDefaultValidator{}, &sshCertDefaultValidator{},
// Ensure that all principal names are allowed // Ensure that all principal names are allowed
newSSHNamePolicyValidator(p.sshHostPolicy, nil), newSSHNamePolicyValidator(p.ctl.GetPolicy().GetSSHHost(), nil),
), nil ), nil
} }

View file

@ -17,7 +17,6 @@ import (
"go.step.sm/crypto/sshutil" "go.step.sm/crypto/sshutil"
"go.step.sm/crypto/x509util" "go.step.sm/crypto/x509util"
"github.com/smallstep/certificates/authority/policy"
"github.com/smallstep/certificates/errs" "github.com/smallstep/certificates/errs"
) )
@ -96,9 +95,6 @@ type OIDC struct {
configuration openIDConfiguration configuration openIDConfiguration
keyStore *keyStore keyStore *keyStore
ctl *Controller ctl *Controller
x509Policy policy.X509Policy
sshHostPolicy policy.HostPolicy
sshUserPolicy policy.UserPolicy
} }
func sanitizeEmail(email string) string { func sanitizeEmail(email string) string {
@ -201,22 +197,7 @@ func (o *OIDC) Init(config Config) (err error) {
return err return err
} }
// Initialize the x509 allow/deny policy engine o.ctl, err = NewController(o, o.Claims, config, o.Options)
if o.x509Policy, err = policy.NewX509PolicyEngine(o.Options.GetX509Options()); err != nil {
return err
}
// Initialize the SSH allow/deny policy engine for user certificates
if o.sshUserPolicy, err = policy.NewSSHUserPolicyEngine(o.Options.GetSSHOptions()); err != nil {
return err
}
// Initialize the SSH allow/deny policy engine for host certificates
if o.sshHostPolicy, err = policy.NewSSHHostPolicyEngine(o.Options.GetSSHOptions()); err != nil {
return err
}
o.ctl, err = NewController(o, o.Claims, config)
return return
} }
@ -374,7 +355,7 @@ func (o *OIDC) AuthorizeSign(ctx context.Context, token string) ([]SignOption, e
// validators // validators
defaultPublicKeyValidator{}, defaultPublicKeyValidator{},
newValidityValidator(o.ctl.Claimer.MinTLSCertDuration(), o.ctl.Claimer.MaxTLSCertDuration()), newValidityValidator(o.ctl.Claimer.MinTLSCertDuration(), o.ctl.Claimer.MaxTLSCertDuration()),
newX509NamePolicyValidator(o.x509Policy), newX509NamePolicyValidator(o.ctl.GetPolicy().GetX509()),
}, nil }, nil
} }
@ -462,7 +443,7 @@ func (o *OIDC) AuthorizeSSHSign(ctx context.Context, token string) ([]SignOption
// Require all the fields in the SSH certificate // Require all the fields in the SSH certificate
&sshCertDefaultValidator{}, &sshCertDefaultValidator{},
// Ensure that all principal names are allowed // Ensure that all principal names are allowed
newSSHNamePolicyValidator(o.sshHostPolicy, o.sshUserPolicy), newSSHNamePolicyValidator(o.ctl.GetPolicy().GetSSHHost(), o.ctl.GetPolicy().GetSSHUser()),
), nil ), nil
} }

View file

@ -0,0 +1,65 @@
package provisioner
import "github.com/smallstep/certificates/authority/policy"
type policyEngine struct {
x509Policy policy.X509Policy
sshHostPolicy policy.HostPolicy
sshUserPolicy policy.UserPolicy
}
func newPolicyEngine(options *Options) (*policyEngine, error) {
if options == nil {
return nil, nil
}
var (
x509Policy policy.X509Policy
sshHostPolicy policy.HostPolicy
sshUserPolicy policy.UserPolicy
err error
)
// Initialize the x509 allow/deny policy engine
if x509Policy, err = policy.NewX509PolicyEngine(options.GetX509Options()); err != nil {
return nil, err
}
// Initialize the SSH allow/deny policy engine for host certificates
if sshHostPolicy, err = policy.NewSSHHostPolicyEngine(options.GetSSHOptions()); err != nil {
return nil, err
}
// Initialize the SSH allow/deny policy engine for user certificates
if sshUserPolicy, err = policy.NewSSHUserPolicyEngine(options.GetSSHOptions()); err != nil {
return nil, err
}
return &policyEngine{
x509Policy: x509Policy,
sshHostPolicy: sshHostPolicy,
sshUserPolicy: sshUserPolicy,
}, nil
}
func (p *policyEngine) GetX509() policy.X509Policy {
if p == nil {
return nil
}
return p.x509Policy
}
func (p *policyEngine) GetSSHHost() policy.HostPolicy {
if p == nil {
return nil
}
return p.sshHostPolicy
}
func (p *policyEngine) GetSSHUser() policy.UserPolicy {
if p == nil {
return nil
}
return p.sshUserPolicy
}

View file

@ -5,8 +5,6 @@ import (
"time" "time"
"github.com/pkg/errors" "github.com/pkg/errors"
"github.com/smallstep/certificates/authority/policy"
) )
// SCEP is the SCEP provisioner type, an entity that can authorize the // SCEP is the SCEP provisioner type, an entity that can authorize the
@ -36,7 +34,6 @@ type SCEP struct {
ctl *Controller ctl *Controller
secretChallengePassword string secretChallengePassword string
encryptionAlgorithm int encryptionAlgorithm int
x509Policy policy.X509Policy
} }
// GetID returns the provisioner unique identifier. // GetID returns the provisioner unique identifier.
@ -113,12 +110,7 @@ func (s *SCEP) Init(config Config) (err error) {
// TODO: add other, SCEP specific, options? // TODO: add other, SCEP specific, options?
// Initialize the x509 allow/deny policy engine s.ctl, err = NewController(s, s.Claims, config, s.Options)
if s.x509Policy, err = policy.NewX509PolicyEngine(s.Options.GetX509Options()); err != nil {
return err
}
s.ctl, err = NewController(s, s.Claims, config)
return return
} }
@ -135,7 +127,7 @@ func (s *SCEP) AuthorizeSign(ctx context.Context, token string) ([]SignOption, e
// validators // validators
newPublicKeyMinimumLengthValidator(s.MinimumPublicKeyLength), newPublicKeyMinimumLengthValidator(s.MinimumPublicKeyLength),
newValidityValidator(s.ctl.Claimer.MinTLSCertDuration(), s.ctl.Claimer.MaxTLSCertDuration()), newValidityValidator(s.ctl.Claimer.MinTLSCertDuration(), s.ctl.Claimer.MaxTLSCertDuration()),
newX509NamePolicyValidator(s.x509Policy), newX509NamePolicyValidator(s.ctl.GetPolicy().GetX509()),
}, nil }, nil
} }

View file

@ -8,9 +8,11 @@ import (
"time" "time"
"github.com/pkg/errors" "github.com/pkg/errors"
"github.com/smallstep/certificates/errs"
"go.step.sm/crypto/jose"
"golang.org/x/crypto/ssh" "golang.org/x/crypto/ssh"
"go.step.sm/crypto/jose"
"github.com/smallstep/certificates/errs"
) )
// sshPOPPayload extends jwt.Claims with step attributes. // sshPOPPayload extends jwt.Claims with step attributes.
@ -92,12 +94,10 @@ func (p *SSHPOP) Init(config Config) (err error) {
return errors.New("provisioner public SSH validation keys cannot be empty") return errors.New("provisioner public SSH validation keys cannot be empty")
} }
// TODO(hs): initialize the policy engine and add it as an SSH cert validator
p.sshPubKeys = config.SSHKeys p.sshPubKeys = config.SSHKeys
config.Audiences = config.Audiences.WithFragment(p.GetIDForToken()) config.Audiences = config.Audiences.WithFragment(p.GetIDForToken())
p.ctl, err = NewController(p, p.Claims, config) p.ctl, err = NewController(p, p.Claims, config, nil)
return return
} }

View file

@ -184,7 +184,7 @@ func generateJWK() (*JWK, error) {
} }
p.ctl, err = NewController(p, p.Claims, Config{ p.ctl, err = NewController(p, p.Claims, Config{
Audiences: testAudiences, Audiences: testAudiences,
}) }, nil)
return p, err return p, err
} }
@ -219,7 +219,7 @@ func generateK8sSA(inputPubKey interface{}) (*K8sSA, error) {
} }
p.ctl, err = NewController(p, p.Claims, Config{ p.ctl, err = NewController(p, p.Claims, Config{
Audiences: testAudiences, Audiences: testAudiences,
}) }, nil)
return p, err return p, err
} }
@ -256,7 +256,7 @@ func generateSSHPOP() (*SSHPOP, error) {
} }
p.ctl, err = NewController(p, p.Claims, Config{ p.ctl, err = NewController(p, p.Claims, Config{
Audiences: testAudiences, Audiences: testAudiences,
}) }, nil)
return p, err return p, err
} }
@ -305,7 +305,7 @@ M46l92gdOozT
} }
p.ctl, err = NewController(p, p.Claims, Config{ p.ctl, err = NewController(p, p.Claims, Config{
Audiences: testAudiences, Audiences: testAudiences,
}) }, nil)
return p, err return p, err
} }
@ -343,7 +343,7 @@ func generateOIDC() (*OIDC, error) {
} }
p.ctl, err = NewController(p, p.Claims, Config{ p.ctl, err = NewController(p, p.Claims, Config{
Audiences: testAudiences, Audiences: testAudiences,
}) }, nil)
return p, err return p, err
} }
@ -373,7 +373,7 @@ func generateGCP() (*GCP, error) {
} }
p.ctl, err = NewController(p, p.Claims, Config{ p.ctl, err = NewController(p, p.Claims, Config{
Audiences: testAudiences.WithFragment("gcp/" + name), Audiences: testAudiences.WithFragment("gcp/" + name),
}) }, nil)
return p, err return p, err
} }
@ -411,7 +411,7 @@ func generateAWS() (*AWS, error) {
} }
p.ctl, err = NewController(p, p.Claims, Config{ p.ctl, err = NewController(p, p.Claims, Config{
Audiences: testAudiences.WithFragment("aws/" + name), Audiences: testAudiences.WithFragment("aws/" + name),
}) }, nil)
return p, err return p, err
} }
@ -518,7 +518,7 @@ func generateAWSV1Only() (*AWS, error) {
} }
p.ctl, err = NewController(p, p.Claims, Config{ p.ctl, err = NewController(p, p.Claims, Config{
Audiences: testAudiences.WithFragment("aws/" + name), Audiences: testAudiences.WithFragment("aws/" + name),
}) }, nil)
return p, err return p, err
} }
@ -608,7 +608,7 @@ func generateAzure() (*Azure, error) {
} }
p.ctl, err = NewController(p, p.Claims, Config{ p.ctl, err = NewController(p, p.Claims, Config{
Audiences: testAudiences, Audiences: testAudiences,
}) }, nil)
return p, err return p, err
} }

View file

@ -8,11 +8,12 @@ import (
"time" "time"
"github.com/pkg/errors" "github.com/pkg/errors"
"github.com/smallstep/certificates/authority/policy"
"github.com/smallstep/certificates/errs"
"go.step.sm/crypto/jose" "go.step.sm/crypto/jose"
"go.step.sm/crypto/sshutil" "go.step.sm/crypto/sshutil"
"go.step.sm/crypto/x509util" "go.step.sm/crypto/x509util"
"github.com/smallstep/certificates/errs"
) )
// x5cPayload extends jwt.Claims with step attributes. // x5cPayload extends jwt.Claims with step attributes.
@ -27,17 +28,14 @@ type x5cPayload struct {
// signature requests. // signature requests.
type X5C struct { type X5C struct {
*base *base
ID string `json:"-"` ID string `json:"-"`
Type string `json:"type"` Type string `json:"type"`
Name string `json:"name"` Name string `json:"name"`
Roots []byte `json:"roots"` Roots []byte `json:"roots"`
Claims *Claims `json:"claims,omitempty"` Claims *Claims `json:"claims,omitempty"`
Options *Options `json:"options,omitempty"` Options *Options `json:"options,omitempty"`
ctl *Controller ctl *Controller
rootPool *x509.CertPool rootPool *x509.CertPool
x509Policy policy.X509Policy
sshHostPolicy policy.HostPolicy
sshUserPolicy policy.UserPolicy
} }
// GetID returns the provisioner unique identifier. The name and credential id // GetID returns the provisioner unique identifier. The name and credential id
@ -124,23 +122,8 @@ func (p *X5C) Init(config Config) (err error) {
return errors.Errorf("no x509 certificates found in roots attribute for provisioner '%s'", p.GetName()) return errors.Errorf("no x509 certificates found in roots attribute for provisioner '%s'", p.GetName())
} }
// Initialize the x509 allow/deny policy engine
if p.x509Policy, err = policy.NewX509PolicyEngine(p.Options.GetX509Options()); err != nil {
return err
}
// Initialize the SSH allow/deny policy engine for user certificates
if p.sshUserPolicy, err = policy.NewSSHUserPolicyEngine(p.Options.GetSSHOptions()); err != nil {
return err
}
// Initialize the SSH allow/deny policy engine for host certificates
if p.sshHostPolicy, err = policy.NewSSHHostPolicyEngine(p.Options.GetSSHOptions()); err != nil {
return err
}
config.Audiences = config.Audiences.WithFragment(p.GetIDForToken()) config.Audiences = config.Audiences.WithFragment(p.GetIDForToken())
p.ctl, err = NewController(p, p.Claims, config) p.ctl, err = NewController(p, p.Claims, config, p.Options)
return return
} }
@ -252,7 +235,7 @@ func (p *X5C) AuthorizeSign(ctx context.Context, token string) ([]SignOption, er
defaultSANsValidator(claims.SANs), defaultSANsValidator(claims.SANs),
defaultPublicKeyValidator{}, defaultPublicKeyValidator{},
newValidityValidator(p.ctl.Claimer.MinTLSCertDuration(), p.ctl.Claimer.MaxTLSCertDuration()), newValidityValidator(p.ctl.Claimer.MinTLSCertDuration(), p.ctl.Claimer.MaxTLSCertDuration()),
newX509NamePolicyValidator(p.x509Policy), newX509NamePolicyValidator(p.ctl.GetPolicy().GetX509()),
}, nil }, nil
} }
@ -338,6 +321,6 @@ func (p *X5C) AuthorizeSSHSign(ctx context.Context, token string) ([]SignOption,
// Require all the fields in the SSH certificate // Require all the fields in the SSH certificate
&sshCertDefaultValidator{}, &sshCertDefaultValidator{},
// Ensure that all principal names are allowed // Ensure that all principal names are allowed
newSSHNamePolicyValidator(p.sshHostPolicy, p.sshUserPolicy), newSSHNamePolicyValidator(p.ctl.GetPolicy().GetSSHHost(), p.ctl.GetPolicy().GetSSHUser()),
), nil ), nil
} }