diff --git a/authority/provisioner/oidc.go b/authority/provisioner/oidc.go index 70675ba7..22c3afab 100644 --- a/authority/provisioner/oidc.go +++ b/authority/provisioner/oidc.go @@ -392,7 +392,15 @@ func (o *OIDC) AuthorizeSSHSign(ctx context.Context, token string) ([]SignOption data.AddCriticalOption(k, v) } - templateOptions, err := TemplateSSHOptions(o.Options, data) + // Use the default template unless no-templates are configured and email is + // an admin, in that case we will use the parameters in the request. + isAdmin := o.IsAdmin(claims.Email) + defaultTemplate := sshutil.DefaultCertificate + if isAdmin && !o.Options.GetSSHOptions().HasTemplate() { + defaultTemplate = sshutil.DefaultAdminCertificate + } + + templateOptions, err := CustomSSHTemplateOptions(o.Options, data, defaultTemplate) if err != nil { return nil, errs.Wrap(http.StatusInternalServerError, err, "jwk.AuthorizeSign") } @@ -401,7 +409,13 @@ func (o *OIDC) AuthorizeSSHSign(ctx context.Context, token string) ([]SignOption // Admin users can use any principal, and can sign user and host certificates. // Non-admin users can only use principals returned by the identityFunc, and // can only sign user certificates. - if !o.IsAdmin(claims.Email) { + if isAdmin { + signOptions = append(signOptions, &sshCertOptionsRequireValidator{ + CertType: true, + KeyID: true, + Principals: true, + }) + } else { signOptions = append(signOptions, sshCertOptionsValidator(SignSSHOptions{ CertType: SSHUserCert, Principals: iden.Usernames, diff --git a/sshutil/templates.go b/sshutil/templates.go index f51b46f6..2565c4fd 100644 --- a/sshutil/templates.go +++ b/sshutil/templates.go @@ -1,5 +1,6 @@ package sshutil +// Variables used to hold template data. const ( TypeKey = "Type" KeyIDKey = "KeyID" @@ -101,7 +102,7 @@ func (t TemplateData) SetType(typ CertType) { t.Set(TypeKey, typ.String()) } -// SetType sets the certificate key id in the template data. +// SetKeyID sets the certificate key id in the template data. func (t TemplateData) SetKeyID(id string) { t.Set(KeyIDKey, id) } @@ -148,13 +149,25 @@ const DefaultCertificate = `{ "criticalOptions": {{ toJson .CriticalOptions }} }` +// DefaultAdminCertificate is the template used by an admin user in a OIDC +// provisioner. +const DefaultAdminCertificate = `{ + "type": "{{ .Insecure.CR.Type }}", + "keyId": "{{ .Insecure.CR.KeyID }}", + "principals": {{ toJson .Insecure.CR.Principals }} +{{- if eq .Insecure.CR.Type "user" }} + , "extensions": {{ toJson .Extensions }}, + "criticalOptions": {{ toJson .CriticalOptions }} +{{- end }} +}` + +// DefaultIIDCertificate is the default template for IID provisioners. By +// default certificate type will be set always to host, key id to the instance +// id. Principals will be only enforced by the provisioner if disableCustomSANs +// is set to true. const DefaultIIDCertificate = `{ "type": "{{ .Type }}", -{{- if .Insecure.CR.KeyID }} - "keyId": "{{ .Insecure.CR.KeyID }}", -{{- else }} "keyId": "{{ .KeyID }}", -{{- end}} {{- if .Insecure.CR.Principals }} "principals": {{ toJson .Insecure.CR.Principals }}, {{- else }} @@ -163,6 +176,9 @@ const DefaultIIDCertificate = `{ "extensions": {{ toJson .Extensions }} }` +// CertificateRequestTemplate is the template used for provisioners that accepts +// any certificate request. The provisioner must validate that type, keyId and +// principals are passed in the request. const CertificateRequestTemplate = `{ "type": "{{ .Insecure.CR.Type }}", "keyId": "{{ .Insecure.CR.KeyID }}",