Use SSHOptions inside provisioner options.
This commit is contained in:
parent
d82bdc1a00
commit
aa657cdb4b
12 changed files with 123 additions and 154 deletions
|
@ -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")
|
||||||
}
|
}
|
||||||
|
|
|
@ -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")
|
||||||
}
|
}
|
||||||
|
|
|
@ -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")
|
||||||
}
|
}
|
||||||
|
|
|
@ -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")
|
||||||
}
|
}
|
||||||
|
|
|
@ -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")
|
||||||
}
|
}
|
||||||
|
|
|
@ -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")
|
||||||
}
|
}
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
@ -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),
|
||||||
|
|
|
@ -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
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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")
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue