forked from TrueCloudLab/certificates
Add support for setting individual password for ssh and tls keys
This change add the following flags: * --ssh-host-password-file * --ssh-user-password-file Fixes #693
This commit is contained in:
parent
e3acea9704
commit
6729c79253
4 changed files with 130 additions and 23 deletions
|
@ -43,6 +43,8 @@ type Authority struct {
|
|||
linkedCAToken string
|
||||
|
||||
// X509 CA
|
||||
password []byte
|
||||
issuerPassword []byte
|
||||
x509CAService cas.CertificateAuthorityService
|
||||
rootX509Certs []*x509.Certificate
|
||||
rootX509CertPool *x509.CertPool
|
||||
|
@ -53,6 +55,8 @@ type Authority struct {
|
|||
scepService *scep.Service
|
||||
|
||||
// SSH CA
|
||||
sshHostPassword []byte
|
||||
sshUserPassword []byte
|
||||
sshCAUserCertSignKey ssh.Signer
|
||||
sshCAHostCertSignKey ssh.Signer
|
||||
sshCAUserCerts []ssh.PublicKey
|
||||
|
@ -206,6 +210,21 @@ func (a *Authority) init() error {
|
|||
|
||||
var err error
|
||||
|
||||
// Set password if they are not set.
|
||||
var configPassword []byte
|
||||
if a.config.Password != "" {
|
||||
configPassword = []byte(a.config.Password)
|
||||
}
|
||||
if configPassword != nil && a.password == nil {
|
||||
a.password = configPassword
|
||||
}
|
||||
if a.sshHostPassword == nil {
|
||||
a.sshHostPassword = a.password
|
||||
}
|
||||
if a.sshUserPassword == nil {
|
||||
a.sshUserPassword = a.password
|
||||
}
|
||||
|
||||
// Automatically enable admin for all linked cas.
|
||||
if a.linkedCAToken != "" {
|
||||
a.config.AuthorityConfig.EnableAdmin = true
|
||||
|
@ -238,6 +257,11 @@ func (a *Authority) init() error {
|
|||
options = *a.config.AuthorityConfig.Options
|
||||
}
|
||||
|
||||
// Set the issuer password if passed in the flags.
|
||||
if options.CertificateIssuer != nil && a.issuerPassword != nil {
|
||||
options.CertificateIssuer.Password = string(a.issuerPassword)
|
||||
}
|
||||
|
||||
// Read intermediate and create X509 signer for default CAS.
|
||||
if options.Is(casapi.SoftCAS) {
|
||||
options.CertificateChain, err = pemutil.ReadCertificateBundle(a.config.IntermediateCert)
|
||||
|
@ -246,7 +270,7 @@ func (a *Authority) init() error {
|
|||
}
|
||||
options.Signer, err = a.keyManager.CreateSigner(&kmsapi.CreateSignerRequest{
|
||||
SigningKey: a.config.IntermediateKey,
|
||||
Password: []byte(a.config.Password),
|
||||
Password: []byte(a.password),
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
|
@ -315,7 +339,7 @@ func (a *Authority) init() error {
|
|||
if a.config.SSH.HostKey != "" {
|
||||
signer, err := a.keyManager.CreateSigner(&kmsapi.CreateSignerRequest{
|
||||
SigningKey: a.config.SSH.HostKey,
|
||||
Password: []byte(a.config.Password),
|
||||
Password: []byte(a.sshHostPassword),
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
|
@ -341,7 +365,7 @@ func (a *Authority) init() error {
|
|||
if a.config.SSH.UserKey != "" {
|
||||
signer, err := a.keyManager.CreateSigner(&kmsapi.CreateSignerRequest{
|
||||
SigningKey: a.config.SSH.UserKey,
|
||||
Password: []byte(a.config.Password),
|
||||
Password: []byte(a.sshUserPassword),
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
|
@ -420,7 +444,7 @@ func (a *Authority) init() error {
|
|||
}
|
||||
options.Signer, err = a.keyManager.CreateSigner(&kmsapi.CreateSignerRequest{
|
||||
SigningKey: a.config.IntermediateKey,
|
||||
Password: []byte(a.config.Password),
|
||||
Password: []byte(a.password),
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
|
@ -429,7 +453,7 @@ func (a *Authority) init() error {
|
|||
if km, ok := a.keyManager.(kmsapi.Decrypter); ok {
|
||||
options.Decrypter, err = km.CreateDecrypter(&kmsapi.CreateDecrypterRequest{
|
||||
DecryptionKey: a.config.IntermediateKey,
|
||||
Password: []byte(a.config.Password),
|
||||
Password: []byte(a.password),
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
|
@ -475,7 +499,7 @@ func (a *Authority) init() error {
|
|||
}
|
||||
if len(provs) == 0 && !strings.EqualFold(a.config.AuthorityConfig.DeploymentType, "linked") {
|
||||
// Create First Provisioner
|
||||
prov, err := CreateFirstProvisioner(context.Background(), a.adminDB, a.config.Password)
|
||||
prov, err := CreateFirstProvisioner(context.Background(), a.adminDB, string(a.password))
|
||||
if err != nil {
|
||||
return admin.WrapErrorISE(err, "error creating first provisioner")
|
||||
}
|
||||
|
|
|
@ -38,6 +38,42 @@ func WithConfigFile(filename string) Option {
|
|||
}
|
||||
}
|
||||
|
||||
// WithPassword set the password to decrypt the intermediate key as well as the
|
||||
// ssh host and user keys if they are not overridden by other options.
|
||||
func WithPassword(password []byte) Option {
|
||||
return func(a *Authority) (err error) {
|
||||
a.password = password
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
// WithSSHHostPassword set the password to decrypt the key used to sign SSH host
|
||||
// certificates.
|
||||
func WithSSHHostPassword(password []byte) Option {
|
||||
return func(a *Authority) (err error) {
|
||||
a.sshHostPassword = password
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
// WithSSHUserPassword set the password to decrypt the key used to sign SSH user
|
||||
// certificates.
|
||||
func WithSSHUserPassword(password []byte) Option {
|
||||
return func(a *Authority) (err error) {
|
||||
a.sshUserPassword = password
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
// WithIssuerPassword set the password to decrypt the certificate issuer private
|
||||
// key used in RA mode.
|
||||
func WithIssuerPassword(password []byte) Option {
|
||||
return func(a *Authority) (err error) {
|
||||
a.issuerPassword = password
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
// WithDatabase sets an already initialized authority database to a new
|
||||
// authority. This option is intended to be use on graceful reloads.
|
||||
func WithDatabase(db db.AuthDB) Option {
|
||||
|
|
49
ca/ca.go
49
ca/ca.go
|
@ -29,11 +29,13 @@ import (
|
|||
)
|
||||
|
||||
type options struct {
|
||||
configFile string
|
||||
linkedCAToken string
|
||||
password []byte
|
||||
issuerPassword []byte
|
||||
database db.AuthDB
|
||||
configFile string
|
||||
linkedCAToken string
|
||||
password []byte
|
||||
issuerPassword []byte
|
||||
sshHostPassword []byte
|
||||
sshUserPassword []byte
|
||||
database db.AuthDB
|
||||
}
|
||||
|
||||
func (o *options) apply(opts []Option) {
|
||||
|
@ -61,6 +63,22 @@ func WithPassword(password []byte) Option {
|
|||
}
|
||||
}
|
||||
|
||||
// WithSSHHostPassword sets the given password to decrypt the key used to sign
|
||||
// ssh host certificates.
|
||||
func WithSSHHostPassword(password []byte) Option {
|
||||
return func(o *options) {
|
||||
o.sshHostPassword = password
|
||||
}
|
||||
}
|
||||
|
||||
// WithSSHUserPassword sets the given password to decrypt the key used to sign
|
||||
// ssh user certificates.
|
||||
func WithSSHUserPassword(password []byte) Option {
|
||||
return func(o *options) {
|
||||
o.sshUserPassword = password
|
||||
}
|
||||
}
|
||||
|
||||
// WithIssuerPassword sets the given password as the configured certificate
|
||||
// issuer password in the CA options.
|
||||
func WithIssuerPassword(password []byte) Option {
|
||||
|
@ -106,19 +124,14 @@ func New(config *config.Config, opts ...Option) (*CA, error) {
|
|||
|
||||
// Init initializes the CA with the given configuration.
|
||||
func (ca *CA) Init(config *config.Config) (*CA, error) {
|
||||
// Intermediate Password.
|
||||
if len(ca.opts.password) > 0 {
|
||||
ca.config.Password = string(ca.opts.password)
|
||||
// Set password, it's ok to set nil password, the ca will prompt for them if
|
||||
// they are required.
|
||||
opts := []authority.Option{
|
||||
authority.WithPassword(ca.opts.password),
|
||||
authority.WithSSHHostPassword(ca.opts.sshHostPassword),
|
||||
authority.WithSSHUserPassword(ca.opts.sshUserPassword),
|
||||
authority.WithIssuerPassword(ca.opts.issuerPassword),
|
||||
}
|
||||
|
||||
// Certificate issuer password for RA mode.
|
||||
if len(ca.opts.issuerPassword) > 0 {
|
||||
if ca.config.AuthorityConfig != nil && ca.config.AuthorityConfig.CertificateIssuer != nil {
|
||||
ca.config.AuthorityConfig.CertificateIssuer.Password = string(ca.opts.issuerPassword)
|
||||
}
|
||||
}
|
||||
|
||||
var opts []authority.Option
|
||||
if ca.opts.linkedCAToken != "" {
|
||||
opts = append(opts, authority.WithLinkedCAToken(ca.opts.linkedCAToken))
|
||||
}
|
||||
|
@ -337,6 +350,8 @@ func (ca *CA) Reload() error {
|
|||
|
||||
newCA, err := New(config,
|
||||
WithPassword(ca.opts.password),
|
||||
WithSSHHostPassword(ca.opts.sshHostPassword),
|
||||
WithSSHUserPassword(ca.opts.sshUserPassword),
|
||||
WithIssuerPassword(ca.opts.issuerPassword),
|
||||
WithLinkedCAToken(ca.opts.linkedCAToken),
|
||||
WithConfigFile(ca.opts.configFile),
|
||||
|
|
|
@ -30,6 +30,18 @@ var AppCommand = cli.Command{
|
|||
Name: "password-file",
|
||||
Usage: `path to the <file> containing the password to decrypt the
|
||||
intermediate private key.`,
|
||||
},
|
||||
cli.StringFlag{
|
||||
Name: "ssh-host-password-file",
|
||||
Usage: `path to the <file> containing the password to decrypt the
|
||||
private key used to sign SSH host certificates. If the flag is not passed it
|
||||
will default to --password-file.`,
|
||||
},
|
||||
cli.StringFlag{
|
||||
Name: "ssh-user-password-file",
|
||||
Usage: `path to the <file> containing the password to decrypt the
|
||||
private key used to sign SSH user certificates. If the flag is not passed it
|
||||
will default to --password-file.`,
|
||||
},
|
||||
cli.StringFlag{
|
||||
Name: "issuer-password-file",
|
||||
|
@ -51,6 +63,8 @@ certificate issuer private key used in the RA mode.`,
|
|||
// AppAction is the action used when the top command runs.
|
||||
func appAction(ctx *cli.Context) error {
|
||||
passFile := ctx.String("password-file")
|
||||
sshHostPassFile := ctx.String("ssh-host-password-file")
|
||||
sshUserPassFile := ctx.String("ssh-user-password-file")
|
||||
issuerPassFile := ctx.String("issuer-password-file")
|
||||
resolver := ctx.String("resolver")
|
||||
token := ctx.String("token")
|
||||
|
@ -89,6 +103,22 @@ To get a linked authority token:
|
|||
password = bytes.TrimRightFunc(password, unicode.IsSpace)
|
||||
}
|
||||
|
||||
var sshHostPassword []byte
|
||||
if sshHostPassFile != "" {
|
||||
if sshHostPassword, err = ioutil.ReadFile(sshHostPassFile); err != nil {
|
||||
fatal(errors.Wrapf(err, "error reading %s", sshHostPassFile))
|
||||
}
|
||||
sshHostPassword = bytes.TrimRightFunc(sshHostPassword, unicode.IsSpace)
|
||||
}
|
||||
|
||||
var sshUserPassword []byte
|
||||
if sshUserPassFile != "" {
|
||||
if sshUserPassword, err = ioutil.ReadFile(sshUserPassFile); err != nil {
|
||||
fatal(errors.Wrapf(err, "error reading %s", sshUserPassFile))
|
||||
}
|
||||
sshUserPassword = bytes.TrimRightFunc(sshUserPassword, unicode.IsSpace)
|
||||
}
|
||||
|
||||
var issuerPassword []byte
|
||||
if issuerPassFile != "" {
|
||||
if issuerPassword, err = ioutil.ReadFile(issuerPassFile); err != nil {
|
||||
|
@ -108,6 +138,8 @@ To get a linked authority token:
|
|||
srv, err := ca.New(config,
|
||||
ca.WithConfigFile(configFile),
|
||||
ca.WithPassword(password),
|
||||
ca.WithSSHHostPassword(sshHostPassword),
|
||||
ca.WithSSHUserPassword(sshUserPassword),
|
||||
ca.WithIssuerPassword(issuerPassword),
|
||||
ca.WithLinkedCAToken(token))
|
||||
if err != nil {
|
||||
|
|
Loading…
Reference in a new issue