forked from TrueCloudLab/certificates
Set default SSH options if no user options are given.
This commit is contained in:
parent
c17375a10a
commit
a8f4ad1b8e
6 changed files with 67 additions and 27 deletions
|
@ -448,13 +448,18 @@ func (p *AWS) authorizeSSHSign(claims *awsPayload) ([]SignOption, error) {
|
||||||
sshCertificateKeyIDModifier(claims.Subject),
|
sshCertificateKeyIDModifier(claims.Subject),
|
||||||
}
|
}
|
||||||
|
|
||||||
signOptions = append(signOptions, &sshCertificateOptionsValidator{&SSHOptions{
|
// Default to host + known IPs/hostnames
|
||||||
|
defaults := SSHOptions{
|
||||||
CertType: SSHHostCert,
|
CertType: SSHHostCert,
|
||||||
Principals: []string{
|
Principals: []string{
|
||||||
doc.PrivateIP,
|
doc.PrivateIP,
|
||||||
fmt.Sprintf("ip-%s.%s.compute.internal", strings.Replace(doc.PrivateIP, ".", "-", -1), doc.Region),
|
fmt.Sprintf("ip-%s.%s.compute.internal", strings.Replace(doc.PrivateIP, ".", "-", -1), doc.Region),
|
||||||
},
|
},
|
||||||
}})
|
}
|
||||||
|
// Validate user options
|
||||||
|
signOptions = append(signOptions, sshCertificateOptionsValidator(defaults))
|
||||||
|
// Set defaults if not given as user options
|
||||||
|
signOptions = append(signOptions, sshCertificateDefaultsModifier(defaults))
|
||||||
|
|
||||||
return append(signOptions,
|
return append(signOptions,
|
||||||
// set the default extensions
|
// set the default extensions
|
||||||
|
|
|
@ -308,10 +308,15 @@ func (p *Azure) authorizeSSHSign(claims azurePayload, name string) ([]SignOption
|
||||||
sshCertificateKeyIDModifier(name),
|
sshCertificateKeyIDModifier(name),
|
||||||
}
|
}
|
||||||
|
|
||||||
signOptions = append(signOptions, &sshCertificateOptionsValidator{&SSHOptions{
|
// Default to host + known hostnames
|
||||||
|
defaults := SSHOptions{
|
||||||
CertType: SSHHostCert,
|
CertType: SSHHostCert,
|
||||||
Principals: []string{name},
|
Principals: []string{name},
|
||||||
}})
|
}
|
||||||
|
// Validate user options
|
||||||
|
signOptions = append(signOptions, sshCertificateOptionsValidator(defaults))
|
||||||
|
// Set defaults if not given as user options
|
||||||
|
signOptions = append(signOptions, sshCertificateDefaultsModifier(defaults))
|
||||||
|
|
||||||
return append(signOptions,
|
return append(signOptions,
|
||||||
// set the default extensions
|
// set the default extensions
|
||||||
|
|
|
@ -360,13 +360,18 @@ func (p *GCP) authorizeSSHSign(claims *gcpPayload) ([]SignOption, error) {
|
||||||
sshCertificateKeyIDModifier(ce.InstanceName),
|
sshCertificateKeyIDModifier(ce.InstanceName),
|
||||||
}
|
}
|
||||||
|
|
||||||
signOptions = append(signOptions, &sshCertificateOptionsValidator{&SSHOptions{
|
// Default to host + known hostnames
|
||||||
|
defaults := SSHOptions{
|
||||||
CertType: SSHHostCert,
|
CertType: SSHHostCert,
|
||||||
Principals: []string{
|
Principals: []string{
|
||||||
fmt.Sprintf("%s.c.%s.internal", ce.InstanceName, ce.ProjectID),
|
fmt.Sprintf("%s.c.%s.internal", ce.InstanceName, ce.ProjectID),
|
||||||
fmt.Sprintf("%s.%s.c.%s.internal", ce.InstanceName, ce.Zone, ce.ProjectID),
|
fmt.Sprintf("%s.%s.c.%s.internal", ce.InstanceName, ce.Zone, ce.ProjectID),
|
||||||
},
|
},
|
||||||
}})
|
}
|
||||||
|
// Validate user options
|
||||||
|
signOptions = append(signOptions, sshCertificateOptionsValidator(defaults))
|
||||||
|
// Set defaults if not given as user options
|
||||||
|
signOptions = append(signOptions, sshCertificateDefaultsModifier(defaults))
|
||||||
|
|
||||||
return append(signOptions,
|
return append(signOptions,
|
||||||
// set the default extensions
|
// set the default extensions
|
||||||
|
|
|
@ -178,7 +178,7 @@ func (p *JWK) authorizeSSHSign(claims *jwtPayload) ([]SignOption, error) {
|
||||||
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 SSHOptions with the ones in the token
|
||||||
&sshCertificateOptionsValidator{opts},
|
sshCertificateOptionsValidator(*opts),
|
||||||
// set the key id to the token subject
|
// set the key id to the token subject
|
||||||
sshCertificateKeyIDModifier(claims.Subject),
|
sshCertificateKeyIDModifier(claims.Subject),
|
||||||
}
|
}
|
||||||
|
@ -197,6 +197,9 @@ func (p *JWK) authorizeSSHSign(claims *jwtPayload) ([]SignOption, error) {
|
||||||
signOptions = append(signOptions, sshCertificateValidBeforeModifier(opts.ValidBefore.RelativeTime(t).Unix()))
|
signOptions = append(signOptions, sshCertificateValidBeforeModifier(opts.ValidBefore.RelativeTime(t).Unix()))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Default to a user certificate with no principals if not set
|
||||||
|
signOptions = append(signOptions, sshCertificateDefaultsModifier{CertType: SSHUserCert})
|
||||||
|
|
||||||
return append(signOptions,
|
return append(signOptions,
|
||||||
// set the default extensions
|
// set the default extensions
|
||||||
&sshDefaultExtensionModifier{},
|
&sshDefaultExtensionModifier{},
|
||||||
|
|
|
@ -303,20 +303,25 @@ func (o *OIDC) authorizeSSHSign(claims *openIDPayload) ([]SignOption, error) {
|
||||||
sshCertificateKeyIDModifier(claims.Email),
|
sshCertificateKeyIDModifier(claims.Email),
|
||||||
}
|
}
|
||||||
|
|
||||||
// Non-admins are only able to sign user certificates
|
name := SanitizeSSHUserPrincipal(claims.Email)
|
||||||
if o.IsAdmin(claims.Email) {
|
if !sshUserRegex.MatchString(name) {
|
||||||
signOptions = append(signOptions, &sshCertificateOptionsValidator{})
|
return nil, errors.Errorf("invalid principal '%s' from email address '%s'", name, claims.Email)
|
||||||
} else {
|
|
||||||
name := SanitizeSSHUserPrincipal(claims.Email)
|
|
||||||
if !sshUserRegex.MatchString(name) {
|
|
||||||
return nil, errors.Errorf("invalid principal '%s' from email address '%s'", name, claims.Email)
|
|
||||||
}
|
|
||||||
signOptions = append(signOptions, &sshCertificateOptionsValidator{&SSHOptions{
|
|
||||||
CertType: SSHUserCert,
|
|
||||||
Principals: []string{name},
|
|
||||||
}})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Admin users will default to user + name but they can be changed by the
|
||||||
|
// user options. Non-admins are only able to sign user certificates.
|
||||||
|
defaults := SSHOptions{
|
||||||
|
CertType: SSHUserCert,
|
||||||
|
Principals: []string{name},
|
||||||
|
}
|
||||||
|
|
||||||
|
if !o.IsAdmin(claims.Email) {
|
||||||
|
signOptions = append(signOptions, sshCertificateOptionsValidator(defaults))
|
||||||
|
}
|
||||||
|
|
||||||
|
// Default to a user with name as principal if not set
|
||||||
|
signOptions = append(signOptions, sshCertificateDefaultsModifier(defaults))
|
||||||
|
|
||||||
return append(signOptions,
|
return append(signOptions,
|
||||||
// set the default extensions
|
// set the default extensions
|
||||||
&sshDefaultExtensionModifier{},
|
&sshDefaultExtensionModifier{},
|
||||||
|
|
|
@ -143,6 +143,27 @@ func (m sshCertificateValidBeforeModifier) Modify(cert *ssh.Certificate) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// sshCertificateDefaultModifier implements a SSHCertificateModifier that
|
||||||
|
// modifies the certificate with the given options if they are not set.
|
||||||
|
type sshCertificateDefaultsModifier SSHOptions
|
||||||
|
|
||||||
|
// Modify implements the SSHCertificateModifier interface.
|
||||||
|
func (m sshCertificateDefaultsModifier) Modify(cert *ssh.Certificate) error {
|
||||||
|
if cert.CertType == 0 {
|
||||||
|
cert.CertType = sshCertTypeUInt32(m.CertType)
|
||||||
|
}
|
||||||
|
if len(cert.ValidPrincipals) == 0 {
|
||||||
|
cert.ValidPrincipals = m.Principals
|
||||||
|
}
|
||||||
|
if cert.ValidAfter == 0 && !m.ValidAfter.IsZero() {
|
||||||
|
cert.ValidAfter = uint64(m.ValidAfter.Unix())
|
||||||
|
}
|
||||||
|
if cert.ValidBefore == 0 && !m.ValidBefore.IsZero() {
|
||||||
|
cert.ValidBefore = uint64(m.ValidBefore.Unix())
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
// sshDefaultExtensionModifier implements an SSHCertificateModifier that sets
|
// sshDefaultExtensionModifier implements an SSHCertificateModifier that sets
|
||||||
// the default extensions in an SSH certificate.
|
// the default extensions in an SSH certificate.
|
||||||
type sshDefaultExtensionModifier struct{}
|
type sshDefaultExtensionModifier struct{}
|
||||||
|
@ -212,17 +233,13 @@ func (m *sshCertificateValidityModifier) Modify(cert *ssh.Certificate) error {
|
||||||
|
|
||||||
// sshCertificateOptionsValidator validates the user SSHOptions with the ones
|
// sshCertificateOptionsValidator validates the user SSHOptions with the ones
|
||||||
// usually present in the token.
|
// usually present in the token.
|
||||||
type sshCertificateOptionsValidator struct {
|
type sshCertificateOptionsValidator SSHOptions
|
||||||
Want *SSHOptions
|
|
||||||
}
|
|
||||||
|
|
||||||
// Valid implements SSHCertificateOptionsValidator and returns nil if both
|
// Valid implements SSHCertificateOptionsValidator and returns nil if both
|
||||||
// SSHOptions match.
|
// SSHOptions match.
|
||||||
func (v *sshCertificateOptionsValidator) Valid(got SSHOptions) error {
|
func (v sshCertificateOptionsValidator) Valid(got SSHOptions) error {
|
||||||
if v.Want == nil {
|
want := SSHOptions(v)
|
||||||
return nil
|
return want.match(got)
|
||||||
}
|
|
||||||
return v.Want.match(got)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// sshCertificateDefaultValidator implements a simple validator for all the
|
// sshCertificateDefaultValidator implements a simple validator for all the
|
||||||
|
|
Loading…
Reference in a new issue