Use SSHOptions inside provisioner options.

This commit is contained in:
Mariano Cano 2020-07-30 18:44:52 -07:00
parent d82bdc1a00
commit aa657cdb4b
12 changed files with 123 additions and 154 deletions

View file

@ -127,15 +127,14 @@ type awsInstanceIdentityDocument struct {
// https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/instance-identity-documents.html // https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/instance-identity-documents.html
type AWS struct { type AWS struct {
*base *base
Type string `json:"type"` Type string `json:"type"`
Name string `json:"name"` Name string `json:"name"`
Accounts []string `json:"accounts"` Accounts []string `json:"accounts"`
DisableCustomSANs bool `json:"disableCustomSANs"` DisableCustomSANs bool `json:"disableCustomSANs"`
DisableTrustOnFirstUse bool `json:"disableTrustOnFirstUse"` DisableTrustOnFirstUse bool `json:"disableTrustOnFirstUse"`
InstanceAge Duration `json:"instanceAge,omitempty"` InstanceAge Duration `json:"instanceAge,omitempty"`
Claims *Claims `json:"claims,omitempty"` Claims *Claims `json:"claims,omitempty"`
Options *Options `json:"options,omitempty"` Options *Options `json:"options,omitempty"`
SSHOptions *SSHOptions `json:"sshOptions,omitempty"`
claimer *Claimer claimer *Claimer
config *awsConfig config *awsConfig
audiences Audiences audiences Audiences
@ -499,7 +498,7 @@ func (p *AWS) AuthorizeSSHSign(ctx context.Context, token string) ([]SignOption,
data.SetToken(v) data.SetToken(v)
} }
templateOptions, err := CustomSSHTemplateOptions(p.SSHOptions, data, defaultTemplate) templateOptions, err := CustomSSHTemplateOptions(p.Options, data, defaultTemplate)
if err != nil { if err != nil {
return nil, errs.Wrap(http.StatusInternalServerError, err, "aws.AuthorizeSSHSign") return nil, errs.Wrap(http.StatusInternalServerError, err, "aws.AuthorizeSSHSign")
} }

View file

@ -84,16 +84,15 @@ type azurePayload struct {
// and https://docs.microsoft.com/en-us/azure/virtual-machines/windows/instance-metadata-service // and https://docs.microsoft.com/en-us/azure/virtual-machines/windows/instance-metadata-service
type Azure struct { type Azure struct {
*base *base
Type string `json:"type"` Type string `json:"type"`
Name string `json:"name"` Name string `json:"name"`
TenantID string `json:"tenantID"` TenantID string `json:"tenantID"`
ResourceGroups []string `json:"resourceGroups"` ResourceGroups []string `json:"resourceGroups"`
Audience string `json:"audience,omitempty"` Audience string `json:"audience,omitempty"`
DisableCustomSANs bool `json:"disableCustomSANs"` DisableCustomSANs bool `json:"disableCustomSANs"`
DisableTrustOnFirstUse bool `json:"disableTrustOnFirstUse"` DisableTrustOnFirstUse bool `json:"disableTrustOnFirstUse"`
Claims *Claims `json:"claims,omitempty"` Claims *Claims `json:"claims,omitempty"`
Options *Options `json:"options,omitempty"` Options *Options `json:"options,omitempty"`
SSHOptions *SSHOptions `json:"sshOptions,omitempty"`
claimer *Claimer claimer *Claimer
config *azureConfig config *azureConfig
oidcConfig openIDConfiguration oidcConfig openIDConfiguration
@ -367,7 +366,7 @@ func (p *Azure) AuthorizeSSHSign(ctx context.Context, token string) ([]SignOptio
data.SetToken(v) data.SetToken(v)
} }
templateOptions, err := CustomSSHTemplateOptions(p.SSHOptions, data, defaultTemplate) templateOptions, err := CustomSSHTemplateOptions(p.Options, data, defaultTemplate)
if err != nil { if err != nil {
return nil, errs.Wrap(http.StatusInternalServerError, err, "azure.AuthorizeSSHSign") return nil, errs.Wrap(http.StatusInternalServerError, err, "azure.AuthorizeSSHSign")
} }

View file

@ -78,16 +78,15 @@ func newGCPConfig() *gcpConfig {
// https://cloud.google.com/compute/docs/instances/verifying-instance-identity // https://cloud.google.com/compute/docs/instances/verifying-instance-identity
type GCP struct { type GCP struct {
*base *base
Type string `json:"type"` Type string `json:"type"`
Name string `json:"name"` Name string `json:"name"`
ServiceAccounts []string `json:"serviceAccounts"` ServiceAccounts []string `json:"serviceAccounts"`
ProjectIDs []string `json:"projectIDs"` ProjectIDs []string `json:"projectIDs"`
DisableCustomSANs bool `json:"disableCustomSANs"` DisableCustomSANs bool `json:"disableCustomSANs"`
DisableTrustOnFirstUse bool `json:"disableTrustOnFirstUse"` DisableTrustOnFirstUse bool `json:"disableTrustOnFirstUse"`
InstanceAge Duration `json:"instanceAge,omitempty"` InstanceAge Duration `json:"instanceAge,omitempty"`
Claims *Claims `json:"claims,omitempty"` Claims *Claims `json:"claims,omitempty"`
Options *Options `json:"options,omitempty"` Options *Options `json:"options,omitempty"`
SSHOptions *SSHOptions `json:"sshOptions,omitempty"`
claimer *Claimer claimer *Claimer
config *gcpConfig config *gcpConfig
keyStore *keyStore keyStore *keyStore
@ -410,7 +409,7 @@ func (p *GCP) AuthorizeSSHSign(ctx context.Context, token string) ([]SignOption,
data.SetToken(v) data.SetToken(v)
} }
templateOptions, err := CustomSSHTemplateOptions(p.SSHOptions, data, defaultTemplate) templateOptions, err := CustomSSHTemplateOptions(p.Options, data, defaultTemplate)
if err != nil { if err != nil {
return nil, errs.Wrap(http.StatusInternalServerError, err, "gcp.AuthorizeSSHSign") return nil, errs.Wrap(http.StatusInternalServerError, err, "gcp.AuthorizeSSHSign")
} }

View file

@ -34,7 +34,6 @@ type JWK struct {
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"`
SSHOptions *SSHOptions `json:"sshOptions,omitempty"`
claimer *Claimer claimer *Claimer
audiences Audiences audiences Audiences
} }
@ -205,7 +204,7 @@ func (p *JWK) AuthorizeSSHSign(ctx context.Context, token string) ([]SignOption,
opts := claims.Step.SSH opts := claims.Step.SSH
signOptions := []SignOption{ signOptions := []SignOption{
// validates user's SSHOptions with the ones in the token // validates user's SignSSHOptions with the ones in the token
sshCertOptionsValidator(*opts), sshCertOptionsValidator(*opts),
// validate users's KeyID is the token subject. // validate users's KeyID is the token subject.
sshCertOptionsValidator(SignSSHOptions{KeyID: claims.Subject}), sshCertOptionsValidator(SignSSHOptions{KeyID: claims.Subject}),
@ -235,7 +234,7 @@ func (p *JWK) AuthorizeSSHSign(ctx context.Context, token string) ([]SignOption,
data.SetToken(v) data.SetToken(v)
} }
templateOptions, err := TemplateSSHOptions(p.SSHOptions, data) templateOptions, err := TemplateSSHOptions(p.Options, data)
if err != nil { if err != nil {
return nil, errs.Wrap(http.StatusInternalServerError, err, "jwk.AuthorizeSign") return nil, errs.Wrap(http.StatusInternalServerError, err, "jwk.AuthorizeSign")
} }

View file

@ -42,14 +42,13 @@ type k8sSAPayload struct {
// entity trusted to make signature requests. // entity trusted to make signature requests.
type K8sSA struct { type K8sSA struct {
*base *base
Type string `json:"type"` Type string `json:"type"`
Name string `json:"name"` Name string `json:"name"`
PubKeys []byte `json:"publicKeys,omitempty"` PubKeys []byte `json:"publicKeys,omitempty"`
Claims *Claims `json:"claims,omitempty"` Claims *Claims `json:"claims,omitempty"`
Options *Options `json:"options,omitempty"` Options *Options `json:"options,omitempty"`
SSHOptions *SSHOptions `json:"sshOptions,omitempty"` claimer *Claimer
claimer *Claimer audiences Audiences
audiences Audiences
//kauthn kauthn.AuthenticationV1Interface //kauthn kauthn.AuthenticationV1Interface
pubKeys []interface{} pubKeys []interface{}
} }
@ -263,7 +262,7 @@ func (p *K8sSA) AuthorizeSSHSign(ctx context.Context, token string) ([]SignOptio
data.SetToken(v) data.SetToken(v)
} }
templateOptions, err := CustomSSHTemplateOptions(p.SSHOptions, data, sshutil.CertificateRequestTemplate) templateOptions, err := CustomSSHTemplateOptions(p.Options, data, sshutil.CertificateRequestTemplate)
if err != nil { if err != nil {
return nil, errs.Wrap(http.StatusInternalServerError, err, "k8ssa.AuthorizeSSHSign") return nil, errs.Wrap(http.StatusInternalServerError, err, "k8ssa.AuthorizeSSHSign")
} }

View file

@ -54,19 +54,18 @@ type openIDPayload struct {
// ClientSecret is mandatory, but it can be an empty string. // ClientSecret is mandatory, but it can be an empty string.
type OIDC struct { type OIDC struct {
*base *base
Type string `json:"type"` Type string `json:"type"`
Name string `json:"name"` Name string `json:"name"`
ClientID string `json:"clientID"` ClientID string `json:"clientID"`
ClientSecret string `json:"clientSecret"` ClientSecret string `json:"clientSecret"`
ConfigurationEndpoint string `json:"configurationEndpoint"` ConfigurationEndpoint string `json:"configurationEndpoint"`
TenantID string `json:"tenantID,omitempty"` TenantID string `json:"tenantID,omitempty"`
Admins []string `json:"admins,omitempty"` Admins []string `json:"admins,omitempty"`
Domains []string `json:"domains,omitempty"` Domains []string `json:"domains,omitempty"`
Groups []string `json:"groups,omitempty"` Groups []string `json:"groups,omitempty"`
ListenAddress string `json:"listenAddress,omitempty"` ListenAddress string `json:"listenAddress,omitempty"`
Claims *Claims `json:"claims,omitempty"` Claims *Claims `json:"claims,omitempty"`
Options *Options `json:"options,omitempty"` Options *Options `json:"options,omitempty"`
SSHOptions *SSHOptions `json:"sshOptions,omitempty"`
configuration openIDConfiguration configuration openIDConfiguration
keyStore *keyStore keyStore *keyStore
claimer *Claimer claimer *Claimer
@ -393,7 +392,7 @@ func (o *OIDC) AuthorizeSSHSign(ctx context.Context, token string) ([]SignOption
data.AddCriticalOption(k, v) data.AddCriticalOption(k, v)
} }
templateOptions, err := TemplateSSHOptions(o.SSHOptions, data) templateOptions, err := TemplateSSHOptions(o.Options, data)
if err != nil { if err != nil {
return nil, errs.Wrap(http.StatusInternalServerError, err, "jwk.AuthorizeSign") return nil, errs.Wrap(http.StatusInternalServerError, err, "jwk.AuthorizeSign")
} }

View file

@ -25,9 +25,10 @@ func (fn certificateOptionsFunc) Options(so SignOptions) []x509util.Option {
// each provisioner. // each provisioner.
type Options struct { type Options struct {
X509 *X509Options `json:"x509,omitempty"` X509 *X509Options `json:"x509,omitempty"`
SSH *SSHOptions `json:"ssh,omitempty"`
} }
// GetX509Options returns the X.509Options // GetX509Options returns the X.509 options.
func (o *Options) GetX509Options() *X509Options { func (o *Options) GetX509Options() *X509Options {
if o == nil { if o == nil {
return nil return nil
@ -35,6 +36,14 @@ func (o *Options) GetX509Options() *X509Options {
return o.X509 return o.X509
} }
// GetSSHOptions returns the SSH options.
func (o *Options) GetSSHOptions() *SSHOptions {
if o == nil {
return nil
}
return o.SSH
}
// X509Options contains specific options for X.509 certificates. // X509Options contains specific options for X.509 certificates.
type X509Options struct { type X509Options struct {
// Template contains a X.509 certificate template. It can be a JSON template // Template contains a X.509 certificate template. It can be a JSON template

View file

@ -46,6 +46,28 @@ func TestOptions_GetX509Options(t *testing.T) {
} }
} }
func TestOptions_GetSSHOptions(t *testing.T) {
type fields struct {
o *Options
}
tests := []struct {
name string
fields fields
want *SSHOptions
}{
{"ok", fields{&Options{SSH: &SSHOptions{Template: "foo"}}}, &SSHOptions{Template: "foo"}},
{"nil", fields{&Options{}}, nil},
{"nilOptions", fields{nil}, nil},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
if got := tt.fields.o.GetSSHOptions(); !reflect.DeepEqual(got, tt.want) {
t.Errorf("Options.GetSSHOptions() = %v, want %v", got, tt.want)
}
})
}
}
func TestProvisionerX509Options_HasTemplate(t *testing.T) { func TestProvisionerX509Options_HasTemplate(t *testing.T) {
type fields struct { type fields struct {
Template string Template string

View file

@ -1,7 +1,6 @@
package provisioner package provisioner
import ( import (
"fmt"
"reflect" "reflect"
"testing" "testing"
"time" "time"
@ -40,7 +39,7 @@ func TestSSHOptions_Type(t *testing.T) {
func TestSSHOptions_Modify(t *testing.T) { func TestSSHOptions_Modify(t *testing.T) {
type test struct { type test struct {
so *SignSSHOptions so SignSSHOptions
cert *ssh.Certificate cert *ssh.Certificate
valid func(*ssh.Certificate) valid func(*ssh.Certificate)
err error err error
@ -48,21 +47,21 @@ func TestSSHOptions_Modify(t *testing.T) {
tests := map[string](func() test){ tests := map[string](func() test){
"fail/unexpected-cert-type": func() test { "fail/unexpected-cert-type": func() test {
return test{ return test{
so: &SignSSHOptions{CertType: "foo"}, so: SignSSHOptions{CertType: "foo"},
cert: new(ssh.Certificate), cert: new(ssh.Certificate),
err: errors.Errorf("ssh certificate has an unknown type - foo"), err: errors.Errorf("ssh certificate has an unknown type - foo"),
} }
}, },
"fail/validAfter-greater-validBefore": func() test { "fail/validAfter-greater-validBefore": func() test {
return test{ return test{
so: &SignSSHOptions{CertType: "user"}, so: SignSSHOptions{CertType: "user"},
cert: &ssh.Certificate{ValidAfter: uint64(15), ValidBefore: uint64(10)}, cert: &ssh.Certificate{ValidAfter: uint64(15), ValidBefore: uint64(10)},
err: errors.Errorf("ssh certificate valid after cannot be greater than valid before"), err: errors.Errorf("ssh certificate valid after cannot be greater than valid before"),
} }
}, },
"ok/user-cert": func() test { "ok/user-cert": func() test {
return test{ return test{
so: &SignSSHOptions{CertType: "user"}, so: SignSSHOptions{CertType: "user"},
cert: new(ssh.Certificate), cert: new(ssh.Certificate),
valid: func(cert *ssh.Certificate) { valid: func(cert *ssh.Certificate) {
assert.Equals(t, cert.CertType, uint32(ssh.UserCert)) assert.Equals(t, cert.CertType, uint32(ssh.UserCert))
@ -71,7 +70,7 @@ func TestSSHOptions_Modify(t *testing.T) {
}, },
"ok/host-cert": func() test { "ok/host-cert": func() test {
return test{ return test{
so: &SignSSHOptions{CertType: "host"}, so: SignSSHOptions{CertType: "host"},
cert: new(ssh.Certificate), cert: new(ssh.Certificate),
valid: func(cert *ssh.Certificate) { valid: func(cert *ssh.Certificate) {
assert.Equals(t, cert.CertType, uint32(ssh.HostCert)) assert.Equals(t, cert.CertType, uint32(ssh.HostCert))
@ -81,7 +80,7 @@ func TestSSHOptions_Modify(t *testing.T) {
"ok": func() test { "ok": func() test {
va := time.Now().Add(5 * time.Minute) va := time.Now().Add(5 * time.Minute)
vb := time.Now().Add(1 * time.Hour) vb := time.Now().Add(1 * time.Hour)
so := &SignSSHOptions{CertType: "host", KeyID: "foo", Principals: []string{"foo", "bar"}, so := SignSSHOptions{CertType: "host", KeyID: "foo", Principals: []string{"foo", "bar"},
ValidAfter: NewTimeDuration(va), ValidBefore: NewTimeDuration(vb)} ValidAfter: NewTimeDuration(va), ValidBefore: NewTimeDuration(vb)}
return test{ return test{
so: so, so: so,
@ -99,7 +98,7 @@ func TestSSHOptions_Modify(t *testing.T) {
for name, run := range tests { for name, run := range tests {
t.Run(name, func(t *testing.T) { t.Run(name, func(t *testing.T) {
tc := run() tc := run()
if err := tc.so.Modify(tc.cert); err != nil { if err := tc.so.Modify(tc.cert, tc.so); err != nil {
if assert.NotNil(t, tc.err) { if assert.NotNil(t, tc.err) {
assert.HasPrefix(t, err.Error(), tc.err.Error()) assert.HasPrefix(t, err.Error(), tc.err.Error())
} }
@ -222,7 +221,7 @@ func Test_sshCertPrincipalsModifier_Modify(t *testing.T) {
for name, run := range tests { for name, run := range tests {
t.Run(name, func(t *testing.T) { t.Run(name, func(t *testing.T) {
tc := run() tc := run()
if assert.Nil(t, tc.modifier.Modify(tc.cert)) { if assert.Nil(t, tc.modifier.Modify(tc.cert, SignSSHOptions{})) {
assert.Equals(t, tc.cert.ValidPrincipals, tc.expected) assert.Equals(t, tc.cert.ValidPrincipals, tc.expected)
} }
}) })
@ -248,7 +247,7 @@ func Test_sshCertKeyIDModifier_Modify(t *testing.T) {
for name, run := range tests { for name, run := range tests {
t.Run(name, func(t *testing.T) { t.Run(name, func(t *testing.T) {
tc := run() tc := run()
if assert.Nil(t, tc.modifier.Modify(tc.cert)) { if assert.Nil(t, tc.modifier.Modify(tc.cert, SignSSHOptions{})) {
assert.Equals(t, tc.cert.KeyId, tc.expected) assert.Equals(t, tc.cert.KeyId, tc.expected)
} }
}) })
@ -287,7 +286,7 @@ func Test_sshCertTypeModifier_Modify(t *testing.T) {
for name, run := range tests { for name, run := range tests {
t.Run(name, func(t *testing.T) { t.Run(name, func(t *testing.T) {
tc := run() tc := run()
if assert.Nil(t, tc.modifier.Modify(tc.cert)) { if assert.Nil(t, tc.modifier.Modify(tc.cert, SignSSHOptions{})) {
assert.Equals(t, tc.cert.CertType, uint32(tc.expected)) assert.Equals(t, tc.cert.CertType, uint32(tc.expected))
} }
}) })
@ -312,7 +311,7 @@ func Test_sshCertValidAfterModifier_Modify(t *testing.T) {
for name, run := range tests { for name, run := range tests {
t.Run(name, func(t *testing.T) { t.Run(name, func(t *testing.T) {
tc := run() tc := run()
if assert.Nil(t, tc.modifier.Modify(tc.cert)) { if assert.Nil(t, tc.modifier.Modify(tc.cert, SignSSHOptions{})) {
assert.Equals(t, tc.cert.ValidAfter, tc.expected) assert.Equals(t, tc.cert.ValidAfter, tc.expected)
} }
}) })
@ -375,7 +374,7 @@ func Test_sshCertDefaultsModifier_Modify(t *testing.T) {
for name, run := range tests { for name, run := range tests {
t.Run(name, func(t *testing.T) { t.Run(name, func(t *testing.T) {
tc := run() tc := run()
if assert.Nil(t, tc.modifier.Modify(tc.cert)) { if assert.Nil(t, tc.modifier.Modify(tc.cert, SignSSHOptions{})) {
tc.valid(tc.cert) tc.valid(tc.cert)
} }
}) })
@ -476,7 +475,7 @@ func Test_sshDefaultExtensionModifier_Modify(t *testing.T) {
for name, run := range tests { for name, run := range tests {
t.Run(name, func(t *testing.T) { t.Run(name, func(t *testing.T) {
tc := run() tc := run()
if err := tc.modifier.Modify(tc.cert); err != nil { if err := tc.modifier.Modify(tc.cert, SignSSHOptions{}); err != nil {
if assert.NotNil(t, tc.err) { if assert.NotNil(t, tc.err) {
assert.HasPrefix(t, err.Error(), tc.err.Error()) assert.HasPrefix(t, err.Error(), tc.err.Error())
} }
@ -908,7 +907,7 @@ func Test_sshValidityModifier(t *testing.T) {
for name, run := range tests { for name, run := range tests {
t.Run(name, func(t *testing.T) { t.Run(name, func(t *testing.T) {
tt := run() tt := run()
if err := tt.svm.Option(SignSSHOptions{}).Modify(tt.cert); err != nil { if err := tt.svm.Modify(tt.cert, SignSSHOptions{}); err != nil {
if assert.NotNil(t, tt.err) { if assert.NotNil(t, tt.err) {
assert.HasPrefix(t, err.Error(), tt.err.Error()) assert.HasPrefix(t, err.Error(), tt.err.Error())
} }
@ -921,28 +920,6 @@ func Test_sshValidityModifier(t *testing.T) {
} }
} }
func Test_sshModifierFunc_Modify(t *testing.T) {
type args struct {
cert *ssh.Certificate
}
tests := []struct {
name string
f sshModifierFunc
args args
wantErr bool
}{
{"ok", func(cert *ssh.Certificate) error { return nil }, args{&ssh.Certificate{}}, false},
{"fail", func(cert *ssh.Certificate) error { return fmt.Errorf("an error") }, args{&ssh.Certificate{}}, true},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
if err := tt.f.Modify(tt.args.cert); (err != nil) != tt.wantErr {
t.Errorf("sshModifierFunc.Modify() error = %v, wantErr %v", err, tt.wantErr)
}
})
}
}
func Test_sshDefaultDuration_Option(t *testing.T) { func Test_sshDefaultDuration_Option(t *testing.T) {
tm, fn := mockNow() tm, fn := mockNow()
defer fn() defer fn()
@ -998,8 +975,7 @@ func Test_sshDefaultDuration_Option(t *testing.T) {
m := &sshDefaultDuration{ m := &sshDefaultDuration{
Claimer: tt.fields.Claimer, Claimer: tt.fields.Claimer,
} }
v := m.Option(tt.args.o) if err := m.Modify(tt.args.cert, tt.args.o); (err != nil) != tt.wantErr {
if err := v.Modify(tt.args.cert); (err != nil) != tt.wantErr {
t.Errorf("sshDefaultDuration.Option() error = %v, wantErr %v", err, tt.wantErr) t.Errorf("sshDefaultDuration.Option() error = %v, wantErr %v", err, tt.wantErr)
} }
if !reflect.DeepEqual(tt.args.cert, tt.want) { if !reflect.DeepEqual(tt.args.cert, tt.want) {
@ -1008,32 +984,3 @@ func Test_sshDefaultDuration_Option(t *testing.T) {
}) })
} }
} }
func Test_sshLimitDuration_Option(t *testing.T) {
type fields struct {
Claimer *Claimer
NotAfter time.Time
}
type args struct {
o SignSSHOptions
}
tests := []struct {
name string
fields fields
args args
want SSHCertModifier
}{
// TODO: Add test cases.
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
m := &sshLimitDuration{
Claimer: tt.fields.Claimer,
NotAfter: tt.fields.NotAfter,
}
if got := m.Option(tt.args.o); !reflect.DeepEqual(got, tt.want) {
t.Errorf("sshLimitDuration.Option() = %v, want %v", got, tt.want)
}
})
}
}

View file

@ -44,7 +44,7 @@ func (o *SSHOptions) HasTemplate() bool {
// defined in the ProvisionerOptions, the provisioner generated data, and the // defined in the ProvisionerOptions, the provisioner generated data, and the
// user data provided in the request. If no template has been provided, // user data provided in the request. If no template has been provided,
// x509util.DefaultLeafTemplate will be used. // x509util.DefaultLeafTemplate will be used.
func TemplateSSHOptions(o *SSHOptions, data sshutil.TemplateData) (SSHCertificateOptions, error) { func TemplateSSHOptions(o *Options, data sshutil.TemplateData) (SSHCertificateOptions, error) {
return CustomSSHTemplateOptions(o, data, sshutil.DefaultCertificate) return CustomSSHTemplateOptions(o, data, sshutil.DefaultCertificate)
} }
@ -52,15 +52,16 @@ func TemplateSSHOptions(o *SSHOptions, data sshutil.TemplateData) (SSHCertificat
// defined in the ProvisionerOptions, the provisioner generated data and the // defined in the ProvisionerOptions, the provisioner generated data and the
// user data provided in the request. If no template has been provided in the // user data provided in the request. If no template has been provided in the
// ProvisionerOptions, the given template will be used. // ProvisionerOptions, the given template will be used.
func CustomSSHTemplateOptions(o *SSHOptions, data sshutil.TemplateData, defaultTemplate string) (SSHCertificateOptions, error) { func CustomSSHTemplateOptions(o *Options, data sshutil.TemplateData, defaultTemplate string) (SSHCertificateOptions, error) {
if o != nil { opts := o.GetSSHOptions()
if data == nil { if data == nil {
data = sshutil.NewTemplateData() data = sshutil.NewTemplateData()
} }
if opts != nil {
// Add template data if any. // Add template data if any.
if len(o.TemplateData) > 0 { if len(opts.TemplateData) > 0 {
if err := json.Unmarshal(o.TemplateData, &data); err != nil { if err := json.Unmarshal(opts.TemplateData, &data); err != nil {
return nil, errors.Wrap(err, "error unmarshaling template data") return nil, errors.Wrap(err, "error unmarshaling template data")
} }
} }
@ -68,7 +69,7 @@ func CustomSSHTemplateOptions(o *SSHOptions, data sshutil.TemplateData, defaultT
return sshCertificateOptionsFunc(func(so SignSSHOptions) []sshutil.Option { return sshCertificateOptionsFunc(func(so SignSSHOptions) []sshutil.Option {
// We're not provided user data without custom templates. // We're not provided user data without custom templates.
if !o.HasTemplate() { if !opts.HasTemplate() {
return []sshutil.Option{ return []sshutil.Option{
sshutil.WithTemplate(defaultTemplate, data), sshutil.WithTemplate(defaultTemplate, data),
} }
@ -85,15 +86,15 @@ func CustomSSHTemplateOptions(o *SSHOptions, data sshutil.TemplateData, defaultT
} }
// Load a template from a file if Template is not defined. // Load a template from a file if Template is not defined.
if o.Template == "" && o.TemplateFile != "" { if opts.Template == "" && opts.TemplateFile != "" {
return []sshutil.Option{ return []sshutil.Option{
sshutil.WithTemplateFile(o.TemplateFile, data), sshutil.WithTemplateFile(opts.TemplateFile, data),
} }
} }
// Load a template from the Template fields // Load a template from the Template fields
// 1. As a JSON in a string. // 1. As a JSON in a string.
template := strings.TrimSpace(o.Template) template := strings.TrimSpace(opts.Template)
if strings.HasPrefix(template, "{") { if strings.HasPrefix(template, "{") {
return []sshutil.Option{ return []sshutil.Option{
sshutil.WithTemplate(template, data), sshutil.WithTemplate(template, data),

View file

@ -53,9 +53,6 @@ func signSSHCertificate(key crypto.PublicKey, opts SignSSHOptions, signOpts []Si
// modify the ssh.Certificate // modify the ssh.Certificate
case SSHCertModifier: case SSHCertModifier:
mods = append(mods, o) mods = append(mods, o)
// modify the ssh.Certificate given the SSHOptions
case SSHCertOptionModifier:
mods = append(mods, o.Option(opts))
// validate the ssh.Certificate // validate the ssh.Certificate
case SSHCertValidator: case SSHCertValidator:
validators = append(validators, o) validators = append(validators, o)
@ -77,13 +74,13 @@ func signSSHCertificate(key crypto.PublicKey, opts SignSSHOptions, signOpts []Si
} }
// Use opts to modify the certificate // Use opts to modify the certificate
if err := opts.Modify(cert); err != nil { if err := opts.Modify(cert, opts); err != nil {
return nil, err return nil, err
} }
// Use provisioner modifiers // Use provisioner modifiers
for _, m := range mods { for _, m := range mods {
if err := m.Modify(cert); err != nil { if err := m.Modify(cert, opts); err != nil {
return nil, err return nil, err
} }
} }

View file

@ -26,15 +26,14 @@ type x5cPayload struct {
// signature requests. // signature requests.
type X5C struct { type X5C struct {
*base *base
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"`
SSHOptions *SSHOptions `json:"sshOptions,omitempty"` claimer *Claimer
claimer *Claimer audiences Audiences
audiences Audiences rootPool *x509.CertPool
rootPool *x509.CertPool
} }
// GetID returns the provisioner unique identifier. The name and credential id // GetID returns the provisioner unique identifier. The name and credential id
@ -277,7 +276,7 @@ func (p *X5C) AuthorizeSSHSign(ctx context.Context, token string) ([]SignOption,
data.SetToken(v) data.SetToken(v)
} }
templateOptions, err := TemplateSSHOptions(p.SSHOptions, data) templateOptions, err := TemplateSSHOptions(p.Options, data)
if err != nil { if err != nil {
return nil, errs.Wrap(http.StatusInternalServerError, err, "x5c.AuthorizeSSHSign") return nil, errs.Wrap(http.StatusInternalServerError, err, "x5c.AuthorizeSSHSign")
} }