Add initial template support for iid provisisioners.

This commit is contained in:
Mariano Cano 2020-07-29 18:05:35 -07:00
parent 8e7bf96769
commit 6c36ceb158
3 changed files with 111 additions and 78 deletions

View file

@ -17,6 +17,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/jose" "github.com/smallstep/cli/jose"
) )
@ -126,14 +127,15 @@ 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
@ -468,34 +470,42 @@ func (p *AWS) AuthorizeSSHSign(ctx context.Context, token string) ([]SignOption,
doc := claims.document doc := claims.document
signOptions := []SignOption{ // Validated principals.
// set the key id to the instance id principals := []string{
sshCertKeyIDModifier(doc.InstanceID), doc.PrivateIP,
} fmt.Sprintf("ip-%s.%s.compute.internal", strings.Replace(doc.PrivateIP, ".", "-", -1), doc.Region),
// Only enforce known principals if disable custom sans is true.
var principals []string
if p.DisableCustomSANs {
principals = []string{
doc.PrivateIP,
fmt.Sprintf("ip-%s.%s.compute.internal", strings.Replace(doc.PrivateIP, ".", "-", -1), doc.Region),
}
} }
// Default to cert type to host // Default to cert type to host
defaults := SignSSHOptions{ defaults := SignSSHOptions{
CertType: SSHHostCert, CertType: SSHHostCert,
Principals: principals, }
defaultTemplate := sshutil.DefaultIIDCertificate
// Only enforce known principals if disable custom sans is true.
if p.DisableCustomSANs {
defaults.Principals = principals
defaultTemplate = sshutil.DefaultCertificate
} }
// Validate user options // Validate user options
signOptions = append(signOptions, sshCertOptionsValidator(defaults)) signOptions := []SignOption{
// Set defaults if not given as user options sshCertOptionsValidator(defaults),
signOptions = append(signOptions, sshCertDefaultsModifier(defaults)) }
// Certificate templates.
data := sshutil.CreateTemplateData(sshutil.HostCert, doc.InstanceID, principals)
if v, err := unsafeParseSigned(token); err == nil {
data.SetToken(v)
}
templateOptions, err := CustomSSHTemplateOptions(p.SSHOptions, data, defaultTemplate)
if err != nil {
return nil, errs.Wrap(http.StatusInternalServerError, err, "aws.AuthorizeSSHSign")
}
signOptions = append(signOptions, templateOptions)
return append(signOptions, return append(signOptions,
// Set the default extensions.
&sshDefaultExtensionModifier{},
// 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

View file

@ -14,6 +14,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/jose" "github.com/smallstep/cli/jose"
) )
@ -83,15 +84,16 @@ 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
@ -338,30 +340,40 @@ func (p *Azure) AuthorizeSSHSign(ctx context.Context, token string) ([]SignOptio
if err != nil { if err != nil {
return nil, errs.Wrap(http.StatusInternalServerError, err, "azure.AuthorizeSSHSign") return nil, errs.Wrap(http.StatusInternalServerError, err, "azure.AuthorizeSSHSign")
} }
signOptions := []SignOption{
// set the key id to the instance name // Validated principals
sshCertKeyIDModifier(name), principals := []string{name}
// Default options and template
defaults := SignSSHOptions{
CertType: SSHHostCert,
} }
defaultTemplate := sshutil.DefaultIIDCertificate
// Only enforce known principals if disable custom sans is true. // Only enforce known principals if disable custom sans is true.
var principals []string
if p.DisableCustomSANs { if p.DisableCustomSANs {
principals = []string{name} defaults.Principals = principals
defaultTemplate = sshutil.DefaultCertificate
} }
// Default to host + known hostnames
defaults := SignSSHOptions{
CertType: SSHHostCert,
Principals: principals,
}
// Validate user options // Validate user options
signOptions = append(signOptions, sshCertOptionsValidator(defaults)) signOptions := []SignOption{
// Set defaults if not given as user options sshCertOptionsValidator(defaults),
signOptions = append(signOptions, sshCertDefaultsModifier(defaults)) }
// Certificate templates.
data := sshutil.CreateTemplateData(sshutil.HostCert, name, principals)
if v, err := unsafeParseSigned(token); err == nil {
data.SetToken(v)
}
templateOptions, err := CustomSSHTemplateOptions(p.SSHOptions, data, defaultTemplate)
if err != nil {
return nil, errs.Wrap(http.StatusInternalServerError, err, "azure.AuthorizeSSHSign")
}
signOptions = append(signOptions, templateOptions)
return append(signOptions, return append(signOptions,
// Set the default extensions.
&sshDefaultExtensionModifier{},
// 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

View file

@ -15,6 +15,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/jose" "github.com/smallstep/cli/jose"
) )
@ -77,15 +78,16 @@ 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
@ -379,33 +381,42 @@ func (p *GCP) AuthorizeSSHSign(ctx context.Context, token string) ([]SignOption,
ce := claims.Google.ComputeEngine ce := claims.Google.ComputeEngine
signOptions := []SignOption{ // Validated principals
// set the key id to the instance name principals := []string{
sshCertKeyIDModifier(ce.InstanceName), fmt.Sprintf("%s.c.%s.internal", ce.InstanceName, ce.ProjectID),
fmt.Sprintf("%s.%s.c.%s.internal", ce.InstanceName, ce.Zone, ce.ProjectID),
} }
// Default options and template
defaults := SignSSHOptions{
CertType: SSHHostCert,
}
defaultTemplate := sshutil.DefaultIIDCertificate
// Only enforce known principals if disable custom sans is true. // Only enforce known principals if disable custom sans is true.
var principals []string
if p.DisableCustomSANs { if p.DisableCustomSANs {
principals = []string{ defaults.Principals = principals
fmt.Sprintf("%s.c.%s.internal", ce.InstanceName, ce.ProjectID), defaultTemplate = sshutil.DefaultCertificate
fmt.Sprintf("%s.%s.c.%s.internal", ce.InstanceName, ce.Zone, ce.ProjectID),
}
} }
// Default to host + known hostnames
defaults := SignSSHOptions{
CertType: SSHHostCert,
Principals: principals,
}
// Validate user options // Validate user options
signOptions = append(signOptions, sshCertOptionsValidator(defaults)) signOptions := []SignOption{
// Set defaults if not given as user options sshCertOptionsValidator(defaults),
signOptions = append(signOptions, sshCertDefaultsModifier(defaults)) }
// Certificate templates.
data := sshutil.CreateTemplateData(sshutil.HostCert, ce.InstanceName, principals)
if v, err := unsafeParseSigned(token); err == nil {
data.SetToken(v)
}
templateOptions, err := CustomSSHTemplateOptions(p.SSHOptions, data, defaultTemplate)
if err != nil {
return nil, errs.Wrap(http.StatusInternalServerError, err, "gcp.AuthorizeSSHSign")
}
signOptions = append(signOptions, templateOptions)
return append(signOptions, return append(signOptions,
// Set the default extensions
&sshDefaultExtensionModifier{},
// 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