forked from TrueCloudLab/certificates
Add template support on k8ssa provisioner.
This commit is contained in:
parent
6c36ceb158
commit
a78f7e8913
5 changed files with 62 additions and 24 deletions
|
@ -10,6 +10,7 @@ import (
|
||||||
|
|
||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
"github.com/smallstep/certificates/errs"
|
"github.com/smallstep/certificates/errs"
|
||||||
|
"github.com/smallstep/certificates/sshutil"
|
||||||
"github.com/smallstep/certificates/x509util"
|
"github.com/smallstep/certificates/x509util"
|
||||||
"github.com/smallstep/cli/crypto/pemutil"
|
"github.com/smallstep/cli/crypto/pemutil"
|
||||||
"github.com/smallstep/cli/jose"
|
"github.com/smallstep/cli/jose"
|
||||||
|
@ -41,13 +42,14 @@ 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"`
|
||||||
claimer *Claimer
|
SSHOptions *SSHOptions `json:"sshOptions,omitempty"`
|
||||||
audiences Audiences
|
claimer *Claimer
|
||||||
|
audiences Audiences
|
||||||
//kauthn kauthn.AuthenticationV1Interface
|
//kauthn kauthn.AuthenticationV1Interface
|
||||||
pubKeys []interface{}
|
pubKeys []interface{}
|
||||||
}
|
}
|
||||||
|
@ -249,16 +251,27 @@ func (p *K8sSA) AuthorizeSSHSign(ctx context.Context, token string) ([]SignOptio
|
||||||
if !p.claimer.IsSSHCAEnabled() {
|
if !p.claimer.IsSSHCAEnabled() {
|
||||||
return nil, errs.Unauthorized("k8ssa.AuthorizeSSHSign; sshCA is disabled for k8sSA provisioner %s", p.GetID())
|
return nil, errs.Unauthorized("k8ssa.AuthorizeSSHSign; sshCA is disabled for k8sSA provisioner %s", p.GetID())
|
||||||
}
|
}
|
||||||
if _, err := p.authorizeToken(token, p.audiences.SSHSign); err != nil {
|
claims, err := p.authorizeToken(token, p.audiences.SSHSign)
|
||||||
|
if err != nil {
|
||||||
return nil, errs.Wrap(http.StatusInternalServerError, err, "k8ssa.AuthorizeSSHSign")
|
return nil, errs.Wrap(http.StatusInternalServerError, err, "k8ssa.AuthorizeSSHSign")
|
||||||
}
|
}
|
||||||
|
|
||||||
// Default to a user certificate with no principals if not set
|
// Certificate templates.
|
||||||
signOptions := []SignOption{sshCertDefaultsModifier{CertType: SSHUserCert}}
|
// Set some default variables to be used in the templates.
|
||||||
|
data := sshutil.CreateTemplateData(sshutil.HostCert, claims.ServiceAccountName, []string{claims.ServiceAccountName})
|
||||||
|
if v, err := unsafeParseSigned(token); err == nil {
|
||||||
|
data.SetToken(v)
|
||||||
|
}
|
||||||
|
|
||||||
|
templateOptions, err := CustomSSHTemplateOptions(p.SSHOptions, data, sshutil.CertificateRequestTemplate)
|
||||||
|
if err != nil {
|
||||||
|
return nil, errs.Wrap(http.StatusInternalServerError, err, "k8ssa.AuthorizeSSHSign")
|
||||||
|
}
|
||||||
|
signOptions := []SignOption{templateOptions}
|
||||||
|
|
||||||
return append(signOptions,
|
return append(signOptions,
|
||||||
// Set the default extensions.
|
// Require type, key-id and principals in the SignSSHOptions.
|
||||||
&sshDefaultExtensionModifier{},
|
&sshCertOptionsRequireValidator{CertType: true, KeyID: true, Principals: true},
|
||||||
// Set the validity bounds if not set.
|
// Set the validity bounds if not set.
|
||||||
&sshDefaultDuration{p.claimer},
|
&sshDefaultDuration{p.claimer},
|
||||||
// Validate public key
|
// Validate public key
|
||||||
|
|
|
@ -299,6 +299,26 @@ func (v sshCertOptionsValidator) Valid(got SignSSHOptions) error {
|
||||||
return want.match(got)
|
return want.match(got)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// sshCertOptionsRequireValidator defines which elements in the SignSSHOptions are required.
|
||||||
|
type sshCertOptionsRequireValidator struct {
|
||||||
|
CertType bool
|
||||||
|
KeyID bool
|
||||||
|
Principals bool
|
||||||
|
}
|
||||||
|
|
||||||
|
func (v sshCertOptionsRequireValidator) Valid(got SignSSHOptions) error {
|
||||||
|
switch {
|
||||||
|
case v.CertType && got.CertType == "":
|
||||||
|
return errors.New("ssh certificate certType cannot be empty")
|
||||||
|
case v.KeyID && got.KeyID == "":
|
||||||
|
return errors.New("ssh certificate keyID cannot be empty")
|
||||||
|
case v.Principals && len(got.Principals) == 0:
|
||||||
|
return errors.New("ssh certificate principals cannot be empty")
|
||||||
|
default:
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
type sshCertValidityValidator struct {
|
type sshCertValidityValidator struct {
|
||||||
*Claimer
|
*Claimer
|
||||||
}
|
}
|
||||||
|
|
|
@ -206,8 +206,6 @@ func (a *Authority) GetSSHBastion(ctx context.Context, user string, hostname str
|
||||||
// SignSSH creates a signed SSH certificate with the given public key and options.
|
// SignSSH creates a signed SSH certificate with the given public key and options.
|
||||||
func (a *Authority) SignSSH(ctx context.Context, key ssh.PublicKey, opts provisioner.SignSSHOptions, signOpts ...provisioner.SignOption) (*ssh.Certificate, error) {
|
func (a *Authority) SignSSH(ctx context.Context, key ssh.PublicKey, opts provisioner.SignSSHOptions, signOpts ...provisioner.SignOption) (*ssh.Certificate, error) {
|
||||||
var (
|
var (
|
||||||
err error
|
|
||||||
certType sshutil.CertType
|
|
||||||
certOptions []sshutil.Option
|
certOptions []sshutil.Option
|
||||||
mods []provisioner.SSHCertModifier
|
mods []provisioner.SSHCertModifier
|
||||||
validators []provisioner.SSHCertValidator
|
validators []provisioner.SSHCertValidator
|
||||||
|
@ -216,14 +214,6 @@ func (a *Authority) SignSSH(ctx context.Context, key ssh.PublicKey, opts provisi
|
||||||
// Set backdate with the configured value
|
// Set backdate with the configured value
|
||||||
opts.Backdate = a.config.AuthorityConfig.Backdate.Duration
|
opts.Backdate = a.config.AuthorityConfig.Backdate.Duration
|
||||||
|
|
||||||
// Validate certificate type.
|
|
||||||
if opts.CertType != "" {
|
|
||||||
certType, err = sshutil.CertTypeFromString(opts.CertType)
|
|
||||||
if err != nil {
|
|
||||||
return nil, errs.Wrap(http.StatusBadRequest, err, "authority.SignSSH")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, op := range signOpts {
|
for _, op := range signOpts {
|
||||||
switch o := op.(type) {
|
switch o := op.(type) {
|
||||||
// add options to NewCertificate
|
// add options to NewCertificate
|
||||||
|
@ -251,7 +241,7 @@ func (a *Authority) SignSSH(ctx context.Context, key ssh.PublicKey, opts provisi
|
||||||
|
|
||||||
// Simulated certificate request with request options.
|
// Simulated certificate request with request options.
|
||||||
cr := sshutil.CertificateRequest{
|
cr := sshutil.CertificateRequest{
|
||||||
Type: certType,
|
Type: opts.CertType,
|
||||||
KeyID: opts.KeyID,
|
KeyID: opts.KeyID,
|
||||||
Principals: opts.Principals,
|
Principals: opts.Principals,
|
||||||
Key: key,
|
Key: key,
|
||||||
|
|
|
@ -11,7 +11,7 @@ import "golang.org/x/crypto/ssh"
|
||||||
// passed with the API instead of the validated ones.
|
// passed with the API instead of the validated ones.
|
||||||
type CertificateRequest struct {
|
type CertificateRequest struct {
|
||||||
Key ssh.PublicKey
|
Key ssh.PublicKey
|
||||||
Type CertType
|
Type string
|
||||||
KeyID string
|
KeyID string
|
||||||
Principals []string
|
Principals []string
|
||||||
}
|
}
|
||||||
|
|
|
@ -143,3 +143,18 @@ const DefaultIIDCertificate = `{
|
||||||
{{- end }}
|
{{- end }}
|
||||||
"extensions": {{ toJson .Extensions }}
|
"extensions": {{ toJson .Extensions }}
|
||||||
}`
|
}`
|
||||||
|
|
||||||
|
const CertificateRequestTemplate = `{
|
||||||
|
"type": "{{ .Insecure.CR.Type }}",
|
||||||
|
"keyId": "{{ .Insecure.CR.KeyID }}",
|
||||||
|
"principals": {{ toJson .Insecure.CR.Principals }}
|
||||||
|
{{- if eq .Insecure.CR.Type "user" }}
|
||||||
|
, "extensions": {
|
||||||
|
"permit-X11-forwarding": "",
|
||||||
|
"permit-agent-forwarding": "",
|
||||||
|
"permit-port-forwarding": "",
|
||||||
|
"permit-pty": "",
|
||||||
|
"permit-user-rc": ""
|
||||||
|
}
|
||||||
|
{{- end }}
|
||||||
|
}`
|
||||||
|
|
Loading…
Reference in a new issue