forked from TrueCloudLab/certificates
Work in progress implementation of PKI with helm support
This commit is contained in:
parent
798b90c359
commit
50f7a0d0c0
2 changed files with 369 additions and 138 deletions
150
pki/helm.go
Normal file
150
pki/helm.go
Normal file
|
@ -0,0 +1,150 @@
|
||||||
|
package pki
|
||||||
|
|
||||||
|
import (
|
||||||
|
"io"
|
||||||
|
"text/template"
|
||||||
|
|
||||||
|
"github.com/Masterminds/sprig/v3"
|
||||||
|
"github.com/pkg/errors"
|
||||||
|
authconfig "github.com/smallstep/certificates/authority/config"
|
||||||
|
"github.com/smallstep/certificates/authority/provisioner"
|
||||||
|
"go.step.sm/linkedca"
|
||||||
|
)
|
||||||
|
|
||||||
|
type helmVariables struct {
|
||||||
|
linkedca.Configuration
|
||||||
|
Defaults linkedca.Defaults
|
||||||
|
Password string
|
||||||
|
SSH struct {
|
||||||
|
Enabled bool
|
||||||
|
}
|
||||||
|
TLS authconfig.TLSOptions
|
||||||
|
Provisioners []provisioner.Interface
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *PKI) WriteHelmTemplate(w io.Writer) error {
|
||||||
|
tmpl, err := template.New("helm").Funcs(sprig.TxtFuncMap()).Parse(helmTemplate)
|
||||||
|
if err != nil {
|
||||||
|
return errors.Wrap(err, "error writing helm template")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Delete ssh section if it is not enabled
|
||||||
|
if !p.options.enableSSH {
|
||||||
|
p.Ssh = nil
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := tmpl.Execute(w, helmVariables{
|
||||||
|
Configuration: p.Configuration,
|
||||||
|
Defaults: p.Defaults,
|
||||||
|
Password: "asdf",
|
||||||
|
TLS: authconfig.DefaultTLSOptions,
|
||||||
|
Provisioners: []provisioner.Interface{
|
||||||
|
&provisioner.JWK{
|
||||||
|
Name: p.options.provisioner,
|
||||||
|
Type: "JWK",
|
||||||
|
Key: p.ottPublicKey,
|
||||||
|
EncryptedKey: "",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}); err != nil {
|
||||||
|
return errors.Wrap(err, "error executing helm template")
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
const helmTemplate = `# Helm template
|
||||||
|
inject:
|
||||||
|
enabled: true
|
||||||
|
# Config contains the configuration files ca.json and defaults.json
|
||||||
|
config:
|
||||||
|
files:
|
||||||
|
ca.json:
|
||||||
|
root: {{ first .Root }}
|
||||||
|
federateRoots: []
|
||||||
|
crt: {{ .Intermediate }}
|
||||||
|
key: {{ .IntermediateKey }}
|
||||||
|
{{- if .SSH.Enabled }}
|
||||||
|
ssh:
|
||||||
|
hostKey: {{ .Ssh.HostKey }}
|
||||||
|
userKey: {{ .Ssh.UserKey }}
|
||||||
|
{{- end }}
|
||||||
|
address: {{ .Address }}
|
||||||
|
dnsNames:
|
||||||
|
{{- range .DnsNames }}
|
||||||
|
- {{ . }}
|
||||||
|
{{- end }}
|
||||||
|
logger:
|
||||||
|
format: json
|
||||||
|
db:
|
||||||
|
type: badger
|
||||||
|
dataSource: /home/step/db
|
||||||
|
authority:
|
||||||
|
provisioners:
|
||||||
|
{{- range .Provisioners }}
|
||||||
|
- {{ . | toJson }}
|
||||||
|
{{- end }}
|
||||||
|
tls:
|
||||||
|
cipherSuites:
|
||||||
|
{{- range .TLS.CipherSuites }}
|
||||||
|
- {{ . }}
|
||||||
|
{{- end }}
|
||||||
|
minVersion: {{ .TLS.MinVersion }}
|
||||||
|
maxVersion: {{ .TLS.MaxVersion }}
|
||||||
|
renegotiation: {{ .TLS.Renegotiation }}
|
||||||
|
|
||||||
|
defaults.json:
|
||||||
|
ca-url: {{ .Defaults.CaUrl }}
|
||||||
|
ca-config: {{ .Defaults.CaConfig }}
|
||||||
|
fingerprint: {{ .Defaults.Fingerprint }}
|
||||||
|
root: {{ .Defaults.Root }}
|
||||||
|
|
||||||
|
# Certificates contains the root and intermediate certificate and
|
||||||
|
# optionally the SSH host and user public keys
|
||||||
|
certificates:
|
||||||
|
# intermediate_ca contains the text of the intermediate CA Certificate
|
||||||
|
intermediate_ca: |
|
||||||
|
{{- index .Files .Intermediate | toString | nindent 6 }}
|
||||||
|
|
||||||
|
# root_ca contains the text of the root CA Certificate
|
||||||
|
root_ca: |
|
||||||
|
{{- first .Root | index .Files | toString | nindent 6 }}
|
||||||
|
|
||||||
|
{{- if .Ssh }}
|
||||||
|
# ssh_host_ca contains the text of the public ssh key for the SSH root CA
|
||||||
|
ssh_host_ca: {{ index .Files .Ssh.HostPublicKey | toString }}
|
||||||
|
|
||||||
|
# ssh_user_ca contains the text of the public ssh key for the SSH root CA
|
||||||
|
ssh_user_ca: {{ index .Files .Ssh.UserPublicKey | toString }}
|
||||||
|
{{- end }}
|
||||||
|
|
||||||
|
# Secrets contains the root and intermediate keys and optionally the SSH
|
||||||
|
# private keys
|
||||||
|
secrets:
|
||||||
|
# ca_password contains the password used to encrypt x509.intermediate_ca_key, ssh.host_ca_key and ssh.user_ca_key
|
||||||
|
# This value must be base64 encoded.
|
||||||
|
ca_password: {{ .Password | b64enc }}
|
||||||
|
provisioner_password: {{ .Password | b64enc}}
|
||||||
|
|
||||||
|
x509:
|
||||||
|
# intermediate_ca_key contains the contents of your encrypted intermediate CA key
|
||||||
|
intermediate_ca_key: |
|
||||||
|
{{- index .Files .IntermediateKey | toString | nindent 8 }}
|
||||||
|
|
||||||
|
# root_ca_key contains the contents of your encrypted root CA key
|
||||||
|
# Note that this value can be omitted without impacting the functionality of step-certificates
|
||||||
|
# If supplied, this should be encrypted using a unique password that is not used for encrypting
|
||||||
|
# the intermediate_ca_key, ssh.host_ca_key or ssh.user_ca_key.
|
||||||
|
root_ca_key: |
|
||||||
|
{{- first .RootKey | index .Files | toString | nindent 8 }}
|
||||||
|
|
||||||
|
{{- if .Ssh }}
|
||||||
|
ssh:
|
||||||
|
# ssh_host_ca_key contains the contents of your encrypted SSH Host CA key
|
||||||
|
host_ca_key: |
|
||||||
|
{{- index .Files .Ssh.HostKey | toString | nindent 8 }}
|
||||||
|
|
||||||
|
# ssh_user_ca_key contains the contents of your encrypted SSH User CA key
|
||||||
|
user_ca_key: |
|
||||||
|
{{- index .Files .Ssh.UserKey | toString | nindent 8 }}
|
||||||
|
{{- end }}
|
||||||
|
`
|
357
pki/pki.go
357
pki/pki.go
|
@ -156,96 +156,108 @@ func GetProvisionerKey(caURL, rootFile, kid string) (string, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
type options struct {
|
type options struct {
|
||||||
address string
|
// address string
|
||||||
caURL string
|
// caURL string
|
||||||
dnsNames []string
|
// dnsNames []string
|
||||||
provisioner string
|
provisioner string
|
||||||
enableACME bool
|
enableACME bool
|
||||||
enableSSH bool
|
enableSSH bool
|
||||||
enableAdmin bool
|
enableAdmin bool
|
||||||
noDB bool
|
noDB bool
|
||||||
|
isHelm bool
|
||||||
deploymentType DeploymentType
|
deploymentType DeploymentType
|
||||||
}
|
}
|
||||||
|
|
||||||
// PKIOption is the type of a configuration option on the pki constructor.
|
// PKIOption is the type of a configuration option on the pki constructor.
|
||||||
type PKIOption func(o *options)
|
type PKIOption func(p *PKI)
|
||||||
|
|
||||||
// WithAddress sets the listen address of step-ca.
|
// WithAddress sets the listen address of step-ca.
|
||||||
func WithAddress(s string) PKIOption {
|
func WithAddress(s string) PKIOption {
|
||||||
return func(o *options) {
|
return func(p *PKI) {
|
||||||
o.address = s
|
p.Address = s
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// WithCaUrl sets the default ca-url of step-ca.
|
// WithCaUrl sets the default ca-url of step-ca.
|
||||||
func WithCaUrl(s string) PKIOption {
|
func WithCaUrl(s string) PKIOption {
|
||||||
return func(o *options) {
|
return func(p *PKI) {
|
||||||
o.caURL = s
|
p.Defaults.CaUrl = s
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// WithDNSNames sets the SANs of step-ca.
|
// WithDNSNames sets the SANs of step-ca.
|
||||||
func WithDNSNames(s []string) PKIOption {
|
func WithDNSNames(s []string) PKIOption {
|
||||||
return func(o *options) {
|
return func(p *PKI) {
|
||||||
o.dnsNames = s
|
p.DnsNames = s
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// WithProvisioner defines the name of the default provisioner.
|
// WithProvisioner defines the name of the default provisioner.
|
||||||
func WithProvisioner(s string) PKIOption {
|
func WithProvisioner(s string) PKIOption {
|
||||||
return func(o *options) {
|
return func(p *PKI) {
|
||||||
o.provisioner = s
|
p.options.provisioner = s
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// WithACME enables acme provisioner in step-ca.
|
// WithACME enables acme provisioner in step-ca.
|
||||||
func WithACME() PKIOption {
|
func WithACME() PKIOption {
|
||||||
return func(o *options) {
|
return func(p *PKI) {
|
||||||
o.enableACME = true
|
p.options.enableACME = true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// WithSSH enables ssh in step-ca.
|
// WithSSH enables ssh in step-ca.
|
||||||
func WithSSH() PKIOption {
|
func WithSSH() PKIOption {
|
||||||
return func(o *options) {
|
return func(p *PKI) {
|
||||||
o.enableSSH = true
|
p.options.enableSSH = true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// WithAdmin enables the admin api in step-ca.
|
// WithAdmin enables the admin api in step-ca.
|
||||||
func WithAdmin() PKIOption {
|
func WithAdmin() PKIOption {
|
||||||
return func(o *options) {
|
return func(p *PKI) {
|
||||||
o.enableAdmin = true
|
p.options.enableAdmin = true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// WithNoDB disables the db in step-ca.
|
// WithNoDB disables the db in step-ca.
|
||||||
func WithNoDB() PKIOption {
|
func WithNoDB() PKIOption {
|
||||||
return func(o *options) {
|
return func(p *PKI) {
|
||||||
o.noDB = true
|
p.options.noDB = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// WithHelm configures the pki to create a helm values.yaml.
|
||||||
|
func WithHelm() PKIOption {
|
||||||
|
return func(p *PKI) {
|
||||||
|
p.options.isHelm = true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// WithDeploymentType defines the deployment type of step-ca.
|
// WithDeploymentType defines the deployment type of step-ca.
|
||||||
func WithDeploymentType(dt DeploymentType) PKIOption {
|
func WithDeploymentType(dt DeploymentType) PKIOption {
|
||||||
return func(o *options) {
|
return func(p *PKI) {
|
||||||
o.deploymentType = dt
|
p.options.deploymentType = dt
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// PKI represents the Public Key Infrastructure used by a certificate authority.
|
// PKI represents the Public Key Infrastructure used by a certificate authority.
|
||||||
type PKI struct {
|
type PKI struct {
|
||||||
casOptions apiv1.Options
|
linkedca.Configuration
|
||||||
caService apiv1.CertificateAuthorityService
|
Defaults linkedca.Defaults
|
||||||
caCreator apiv1.CertificateAuthorityCreator
|
casOptions apiv1.Options
|
||||||
root, rootKey, rootFingerprint string
|
caService apiv1.CertificateAuthorityService
|
||||||
intermediate, intermediateKey string
|
caCreator apiv1.CertificateAuthorityCreator
|
||||||
sshHostPubKey, sshHostKey string
|
// root, rootKey, rootFingerprint string
|
||||||
sshUserPubKey, sshUserKey string
|
// intermediate, intermediateKey string
|
||||||
config, defaults string
|
// sshHostPubKey, sshHostKey string
|
||||||
ottPublicKey *jose.JSONWebKey
|
// sshUserPubKey, sshUserKey string
|
||||||
ottPrivateKey *jose.JSONWebEncryption
|
config string
|
||||||
options *options
|
defaults string
|
||||||
|
// rootFingerprint string
|
||||||
|
ottPublicKey *jose.JSONWebKey
|
||||||
|
ottPrivateKey *jose.JSONWebEncryption
|
||||||
|
options *options
|
||||||
}
|
}
|
||||||
|
|
||||||
// New creates a new PKI configuration.
|
// New creates a new PKI configuration.
|
||||||
|
@ -264,20 +276,6 @@ func New(o apiv1.Options, opts ...PKIOption) (*PKI, error) {
|
||||||
caCreator = creator
|
caCreator = creator
|
||||||
}
|
}
|
||||||
|
|
||||||
public := GetPublicPath()
|
|
||||||
private := GetSecretsPath()
|
|
||||||
config := GetConfigPath()
|
|
||||||
|
|
||||||
// Create directories
|
|
||||||
dirs := []string{public, private, config, GetTemplatesPath()}
|
|
||||||
for _, name := range dirs {
|
|
||||||
if _, err := os.Stat(name); os.IsNotExist(err) {
|
|
||||||
if err = os.MkdirAll(name, 0700); err != nil {
|
|
||||||
return nil, errs.FileError(err, name)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// get absolute path for dir/name
|
// get absolute path for dir/name
|
||||||
getPath := func(dir string, name string) (string, error) {
|
getPath := func(dir string, name string) (string, error) {
|
||||||
s, err := filepath.Abs(filepath.Join(dir, name))
|
s, err := filepath.Abs(filepath.Join(dir, name))
|
||||||
|
@ -285,52 +283,96 @@ func New(o apiv1.Options, opts ...PKIOption) (*PKI, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
p := &PKI{
|
p := &PKI{
|
||||||
|
Configuration: linkedca.Configuration{
|
||||||
|
Address: "127.0.0.1:9000",
|
||||||
|
DnsNames: []string{"127.0.0.1"},
|
||||||
|
Ssh: &linkedca.SSH{},
|
||||||
|
Files: make(map[string][]byte),
|
||||||
|
},
|
||||||
casOptions: o,
|
casOptions: o,
|
||||||
caCreator: caCreator,
|
caCreator: caCreator,
|
||||||
caService: caService,
|
caService: caService,
|
||||||
options: &options{
|
options: &options{
|
||||||
provisioner: "step-cli",
|
provisioner: "step-cli",
|
||||||
address: "127.0.0.1:9000",
|
|
||||||
dnsNames: []string{"127.0.0.1"},
|
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
for _, fn := range opts {
|
for _, fn := range opts {
|
||||||
fn(p.options)
|
fn(p)
|
||||||
}
|
}
|
||||||
|
|
||||||
if p.root, err = getPath(public, "root_ca.crt"); err != nil {
|
// Use /home/step as the step path in helm configurations.
|
||||||
return nil, err
|
// Use the current step path when creating pki in files.
|
||||||
}
|
var public, private, config string
|
||||||
if p.rootKey, err = getPath(private, "root_ca_key"); err != nil {
|
if p.options.isHelm {
|
||||||
return nil, err
|
public = "/home/step/certs"
|
||||||
}
|
private = "/home/step/secrets"
|
||||||
if p.intermediate, err = getPath(public, "intermediate_ca.crt"); err != nil {
|
config = "/home/step/config"
|
||||||
return nil, err
|
} else {
|
||||||
}
|
public = GetPublicPath()
|
||||||
if p.intermediateKey, err = getPath(private, "intermediate_ca_key"); err != nil {
|
private = GetSecretsPath()
|
||||||
return nil, err
|
config = GetConfigPath()
|
||||||
}
|
// Create directories
|
||||||
if p.sshHostPubKey, err = getPath(public, "ssh_host_ca_key.pub"); err != nil {
|
dirs := []string{public, private, config, GetTemplatesPath()}
|
||||||
return nil, err
|
for _, name := range dirs {
|
||||||
}
|
if _, err := os.Stat(name); os.IsNotExist(err) {
|
||||||
if p.sshUserPubKey, err = getPath(public, "ssh_user_ca_key.pub"); err != nil {
|
if err = os.MkdirAll(name, 0700); err != nil {
|
||||||
return nil, err
|
return nil, errs.FileError(err, name)
|
||||||
}
|
}
|
||||||
if p.sshHostKey, err = getPath(private, "ssh_host_ca_key"); err != nil {
|
}
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
if p.sshUserKey, err = getPath(private, "ssh_user_ca_key"); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
if len(config) > 0 {
|
|
||||||
if p.config, err = getPath(config, "ca.json"); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
if p.defaults, err = getPath(config, "defaults.json"); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if p.Defaults.CaUrl == "" {
|
||||||
|
p.Defaults.CaUrl = p.DnsNames[0]
|
||||||
|
_, port, err := net.SplitHostPort(p.Address)
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.Wrapf(err, "error parsing %s", p.Address)
|
||||||
|
}
|
||||||
|
if port == "443" {
|
||||||
|
p.Defaults.CaUrl = fmt.Sprintf("https://%s", p.Defaults.CaUrl)
|
||||||
|
} else {
|
||||||
|
p.Defaults.CaUrl = fmt.Sprintf("https://%s:%s", p.Defaults.CaUrl, port)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
root, err := getPath(public, "root_ca.crt")
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
rootKey, err := getPath(private, "root_ca_key")
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
p.Root = []string{root}
|
||||||
|
p.RootKey = []string{rootKey}
|
||||||
|
p.Defaults.Root = root
|
||||||
|
|
||||||
|
if p.Intermediate, err = getPath(public, "intermediate_ca.crt"); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if p.IntermediateKey, err = getPath(private, "intermediate_ca_key"); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if p.Ssh.HostPublicKey, err = getPath(public, "ssh_host_ca_key.pub"); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if p.Ssh.UserPublicKey, err = getPath(public, "ssh_user_ca_key.pub"); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if p.Ssh.HostKey, err = getPath(private, "ssh_host_ca_key"); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if p.Ssh.UserKey, err = getPath(private, "ssh_user_ca_key"); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if p.defaults, err = getPath(config, "defaults.json"); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if p.config, err = getPath(config, "ca.json"); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
p.Defaults.CaConfig = p.config
|
||||||
|
|
||||||
return p, nil
|
return p, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -341,7 +383,7 @@ func (p *PKI) GetCAConfigPath() string {
|
||||||
|
|
||||||
// GetRootFingerprint returns the root fingerprint.
|
// GetRootFingerprint returns the root fingerprint.
|
||||||
func (p *PKI) GetRootFingerprint() string {
|
func (p *PKI) GetRootFingerprint() string {
|
||||||
return p.rootFingerprint
|
return p.Defaults.Fingerprint
|
||||||
}
|
}
|
||||||
|
|
||||||
// SetProvisioner sets the provisioner name of the OTT keys.
|
// SetProvisioner sets the provisioner name of the OTT keys.
|
||||||
|
@ -355,21 +397,21 @@ func (p *PKI) SetProvisioner(s string) {
|
||||||
//
|
//
|
||||||
// Deprecated: this method is deprecated in favor of WithAddress.
|
// Deprecated: this method is deprecated in favor of WithAddress.
|
||||||
func (p *PKI) SetAddress(s string) {
|
func (p *PKI) SetAddress(s string) {
|
||||||
p.options.address = s
|
p.Address = s
|
||||||
}
|
}
|
||||||
|
|
||||||
// SetDNSNames sets the dns names of the CA.
|
// SetDNSNames sets the dns names of the CA.
|
||||||
//
|
//
|
||||||
// Deprecated: this method is deprecated in favor of WithDNSNames.
|
// Deprecated: this method is deprecated in favor of WithDNSNames.
|
||||||
func (p *PKI) SetDNSNames(s []string) {
|
func (p *PKI) SetDNSNames(s []string) {
|
||||||
p.options.dnsNames = s
|
p.DnsNames = s
|
||||||
}
|
}
|
||||||
|
|
||||||
// SetCAURL sets the ca-url to use in the defaults.json.
|
// SetCAURL sets the ca-url to use in the defaults.json.
|
||||||
//
|
//
|
||||||
// Deprecated: this method is deprecated in favor of WithCaUrl.
|
// Deprecated: this method is deprecated in favor of WithCaUrl.
|
||||||
func (p *PKI) SetCAURL(s string) {
|
func (p *PKI) SetCAURL(s string) {
|
||||||
p.options.caURL = s
|
p.Defaults.CaUrl = s
|
||||||
}
|
}
|
||||||
|
|
||||||
// GenerateKeyPairs generates the key pairs used by the certificate authority.
|
// GenerateKeyPairs generates the key pairs used by the certificate authority.
|
||||||
|
@ -408,11 +450,19 @@ func (p *PKI) GenerateRootCertificate(name, org, resource string, pass []byte) (
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// PrivateKey will only be set if we have access to it (SoftCAS).
|
sum := sha256.Sum256(resp.Certificate.Raw)
|
||||||
if err := p.WriteRootCertificate(resp.Certificate, resp.PrivateKey, pass); err != nil {
|
p.Defaults.Fingerprint = strings.ToLower(hex.EncodeToString(sum[:]))
|
||||||
|
p.Files[p.Root[0]] = encodeCertificate(resp.Certificate)
|
||||||
|
p.Files[p.RootKey[0]], err = encodePrivateKey(resp.PrivateKey, pass)
|
||||||
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// PrivateKey will only be set if we have access to it (SoftCAS).
|
||||||
|
// if err := p.WriteRootCertificate(resp.Certificate, resp.PrivateKey, pass); err != nil {
|
||||||
|
// return nil, err
|
||||||
|
// }
|
||||||
|
|
||||||
return resp, nil
|
return resp, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -442,12 +492,24 @@ func (p *PKI) GenerateIntermediateCertificate(name, org, resource string, parent
|
||||||
}
|
}
|
||||||
|
|
||||||
p.casOptions.CertificateAuthority = resp.Name
|
p.casOptions.CertificateAuthority = resp.Name
|
||||||
return p.WriteIntermediateCertificate(resp.Certificate, resp.PrivateKey, pass)
|
p.Files[p.Intermediate] = encodeCertificate(resp.Certificate)
|
||||||
|
p.Files[p.IntermediateKey], err = encodePrivateKey(resp.PrivateKey, pass)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
// return p.WriteIntermediateCertificate(resp.Certificate, resp.PrivateKey, pass)
|
||||||
}
|
}
|
||||||
|
|
||||||
// WriteRootCertificate writes to disk the given certificate and key.
|
// WriteRootCertificate writes to disk the given certificate and key.
|
||||||
func (p *PKI) WriteRootCertificate(rootCrt *x509.Certificate, rootKey interface{}, pass []byte) error {
|
func (p *PKI) WriteRootCertificate(rootCrt *x509.Certificate, rootKey interface{}, pass []byte) error {
|
||||||
if err := fileutil.WriteFile(p.root, pem.EncodeToMemory(&pem.Block{
|
fmt.Println(p.options.isHelm)
|
||||||
|
if p.options.isHelm {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := fileutil.WriteFile(p.Root[0], pem.EncodeToMemory(&pem.Block{
|
||||||
Type: "CERTIFICATE",
|
Type: "CERTIFICATE",
|
||||||
Bytes: rootCrt.Raw,
|
Bytes: rootCrt.Raw,
|
||||||
}), 0600); err != nil {
|
}), 0600); err != nil {
|
||||||
|
@ -455,28 +517,32 @@ func (p *PKI) WriteRootCertificate(rootCrt *x509.Certificate, rootKey interface{
|
||||||
}
|
}
|
||||||
|
|
||||||
if rootKey != nil {
|
if rootKey != nil {
|
||||||
_, err := pemutil.Serialize(rootKey, pemutil.WithPassword(pass), pemutil.ToFile(p.rootKey, 0600))
|
_, err := pemutil.Serialize(rootKey, pemutil.WithPassword(pass), pemutil.ToFile(p.RootKey[0], 0600))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
sum := sha256.Sum256(rootCrt.Raw)
|
sum := sha256.Sum256(rootCrt.Raw)
|
||||||
p.rootFingerprint = strings.ToLower(hex.EncodeToString(sum[:]))
|
p.Defaults.Fingerprint = strings.ToLower(hex.EncodeToString(sum[:]))
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// WriteIntermediateCertificate writes to disk the given certificate and key.
|
// WriteIntermediateCertificate writes to disk the given certificate and key.
|
||||||
func (p *PKI) WriteIntermediateCertificate(crt *x509.Certificate, key interface{}, pass []byte) error {
|
func (p *PKI) WriteIntermediateCertificate(crt *x509.Certificate, key interface{}, pass []byte) error {
|
||||||
if err := fileutil.WriteFile(p.intermediate, pem.EncodeToMemory(&pem.Block{
|
if p.options.isHelm {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := fileutil.WriteFile(p.Intermediate, pem.EncodeToMemory(&pem.Block{
|
||||||
Type: "CERTIFICATE",
|
Type: "CERTIFICATE",
|
||||||
Bytes: crt.Raw,
|
Bytes: crt.Raw,
|
||||||
}), 0600); err != nil {
|
}), 0600); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if key != nil {
|
if key != nil {
|
||||||
_, err := pemutil.Serialize(key, pemutil.WithPassword(pass), pemutil.ToFile(p.intermediateKey, 0600))
|
_, err := pemutil.Serialize(key, pemutil.WithPassword(pass), pemutil.ToFile(p.IntermediateKey, 0600))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -516,8 +582,8 @@ func (p *PKI) GetCertificateAuthority() error {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Issuer is in the RA
|
// Issuer is in the RA
|
||||||
p.intermediate = ""
|
p.Intermediate = ""
|
||||||
p.intermediateKey = ""
|
p.IntermediateKey = ""
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
@ -525,8 +591,8 @@ func (p *PKI) GetCertificateAuthority() error {
|
||||||
// GenerateSSHSigningKeys generates and encrypts a private key used for signing
|
// GenerateSSHSigningKeys generates and encrypts a private key used for signing
|
||||||
// SSH user certificates and a private key used for signing host certificates.
|
// SSH user certificates and a private key used for signing host certificates.
|
||||||
func (p *PKI) GenerateSSHSigningKeys(password []byte) error {
|
func (p *PKI) GenerateSSHSigningKeys(password []byte) error {
|
||||||
var pubNames = []string{p.sshHostPubKey, p.sshUserPubKey}
|
var pubNames = []string{p.Ssh.HostPublicKey, p.Ssh.UserPublicKey}
|
||||||
var privNames = []string{p.sshHostKey, p.sshUserKey}
|
var privNames = []string{p.Ssh.HostKey, p.Ssh.UserKey}
|
||||||
for i := 0; i < 2; i++ {
|
for i := 0; i < 2; i++ {
|
||||||
pub, priv, err := keyutil.GenerateDefaultKeyPair()
|
pub, priv, err := keyutil.GenerateDefaultKeyPair()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -539,13 +605,19 @@ func (p *PKI) GenerateSSHSigningKeys(password []byte) error {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return errors.Wrapf(err, "error converting public key")
|
return errors.Wrapf(err, "error converting public key")
|
||||||
}
|
}
|
||||||
_, err = pemutil.Serialize(priv, pemutil.WithFilename(privNames[i]), pemutil.WithPassword(password))
|
p.Files[pubNames[i]] = ssh.MarshalAuthorizedKey(sshKey)
|
||||||
|
p.Files[privNames[i]], err = encodePrivateKey(priv, password)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if err = fileutil.WriteFile(pubNames[i], ssh.MarshalAuthorizedKey(sshKey), 0600); err != nil {
|
|
||||||
return err
|
// _, err = pemutil.Serialize(priv, pemutil.WithFilename(privNames[i]), pemutil.WithPassword(password))
|
||||||
}
|
// if err != nil {
|
||||||
|
// return err
|
||||||
|
// }
|
||||||
|
// if err = fileutil.WriteFile(pubNames[i], ssh.MarshalAuthorizedKey(sshKey), 0600); err != nil {
|
||||||
|
// return err
|
||||||
|
// }
|
||||||
}
|
}
|
||||||
p.options.enableSSH = true
|
p.options.enableSSH = true
|
||||||
return nil
|
return nil
|
||||||
|
@ -575,22 +647,22 @@ func (p *PKI) TellPKI() {
|
||||||
func (p *PKI) tellPKI() {
|
func (p *PKI) tellPKI() {
|
||||||
ui.Println()
|
ui.Println()
|
||||||
if p.casOptions.Is(apiv1.SoftCAS) {
|
if p.casOptions.Is(apiv1.SoftCAS) {
|
||||||
ui.PrintSelected("Root certificate", p.root)
|
ui.PrintSelected("Root certificate", p.Root[0])
|
||||||
ui.PrintSelected("Root private key", p.rootKey)
|
ui.PrintSelected("Root private key", p.RootKey[0])
|
||||||
ui.PrintSelected("Root fingerprint", p.rootFingerprint)
|
ui.PrintSelected("Root fingerprint", p.Defaults.Fingerprint)
|
||||||
ui.PrintSelected("Intermediate certificate", p.intermediate)
|
ui.PrintSelected("Intermediate certificate", p.Intermediate)
|
||||||
ui.PrintSelected("Intermediate private key", p.intermediateKey)
|
ui.PrintSelected("Intermediate private key", p.IntermediateKey)
|
||||||
} else if p.rootFingerprint != "" {
|
} else if p.Defaults.Fingerprint != "" {
|
||||||
ui.PrintSelected("Root certificate", p.root)
|
ui.PrintSelected("Root certificate", p.Root[0])
|
||||||
ui.PrintSelected("Root fingerprint", p.rootFingerprint)
|
ui.PrintSelected("Root fingerprint", p.Defaults.Fingerprint)
|
||||||
} else {
|
} else {
|
||||||
ui.Printf(`{{ "%s" | red }} {{ "Root certificate:" | bold }} failed to retrieve it from RA`+"\n", ui.IconBad)
|
ui.Printf(`{{ "%s" | red }} {{ "Root certificate:" | bold }} failed to retrieve it from RA`+"\n", ui.IconBad)
|
||||||
}
|
}
|
||||||
if p.options.enableSSH {
|
if p.options.enableSSH {
|
||||||
ui.PrintSelected("SSH user root certificate", p.sshUserPubKey)
|
ui.PrintSelected("SSH user public key", p.Ssh.UserPublicKey)
|
||||||
ui.PrintSelected("SSH user root private key", p.sshUserKey)
|
ui.PrintSelected("SSH user private key", p.Ssh.UserKey)
|
||||||
ui.PrintSelected("SSH host root certificate", p.sshHostPubKey)
|
ui.PrintSelected("SSH host public key", p.Ssh.HostPublicKey)
|
||||||
ui.PrintSelected("SSH host root private key", p.sshHostKey)
|
ui.PrintSelected("SSH host private key", p.Ssh.HostKey)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -637,12 +709,12 @@ func (p *PKI) GenerateConfig(opt ...Option) (*authconfig.Config, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
config := &authconfig.Config{
|
config := &authconfig.Config{
|
||||||
Root: []string{p.root},
|
Root: p.Root,
|
||||||
FederatedRoots: []string{},
|
FederatedRoots: p.FederatedRoots,
|
||||||
IntermediateCert: p.intermediate,
|
IntermediateCert: p.Intermediate,
|
||||||
IntermediateKey: p.intermediateKey,
|
IntermediateKey: p.IntermediateKey,
|
||||||
Address: p.options.address,
|
Address: p.Address,
|
||||||
DNSNames: p.options.dnsNames,
|
DNSNames: p.DnsNames,
|
||||||
Logger: []byte(`{"format": "text"}`),
|
Logger: []byte(`{"format": "text"}`),
|
||||||
DB: &db.Config{
|
DB: &db.Config{
|
||||||
Type: "badger",
|
Type: "badger",
|
||||||
|
@ -685,8 +757,8 @@ func (p *PKI) GenerateConfig(opt ...Option) (*authconfig.Config, error) {
|
||||||
if p.options.enableSSH {
|
if p.options.enableSSH {
|
||||||
enableSSHCA := true
|
enableSSHCA := true
|
||||||
config.SSH = &authconfig.SSHConfig{
|
config.SSH = &authconfig.SSHConfig{
|
||||||
HostKey: p.sshHostKey,
|
HostKey: p.Ssh.HostKey,
|
||||||
UserKey: p.sshUserKey,
|
UserKey: p.Ssh.UserKey,
|
||||||
}
|
}
|
||||||
// Enable SSH authorization for default JWK provisioner
|
// Enable SSH authorization for default JWK provisioner
|
||||||
prov.Claims = &provisioner.Claims{
|
prov.Claims = &provisioner.Claims{
|
||||||
|
@ -776,26 +848,12 @@ func (p *PKI) Save(opt ...Option) error {
|
||||||
return errs.FileError(err, p.config)
|
return errs.FileError(err, p.config)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Generate the CA URL.
|
|
||||||
if p.options.caURL == "" {
|
|
||||||
p.options.caURL = p.options.dnsNames[0]
|
|
||||||
_, port, err := net.SplitHostPort(p.options.address)
|
|
||||||
if err != nil {
|
|
||||||
return errors.Wrapf(err, "error parsing %s", p.options.address)
|
|
||||||
}
|
|
||||||
if port == "443" {
|
|
||||||
p.options.caURL = fmt.Sprintf("https://%s", p.options.caURL)
|
|
||||||
} else {
|
|
||||||
p.options.caURL = fmt.Sprintf("https://%s:%s", p.options.caURL, port)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Generate and write defaults.json
|
// Generate and write defaults.json
|
||||||
defaults := &caDefaults{
|
defaults := &caDefaults{
|
||||||
Root: p.root,
|
Root: p.Defaults.Root,
|
||||||
CAConfig: p.config,
|
CAConfig: p.Defaults.CaConfig,
|
||||||
CAUrl: p.options.caURL,
|
CAUrl: p.Defaults.CaUrl,
|
||||||
Fingerprint: p.rootFingerprint,
|
Fingerprint: p.Defaults.Fingerprint,
|
||||||
}
|
}
|
||||||
b, err = json.MarshalIndent(defaults, "", "\t")
|
b, err = json.MarshalIndent(defaults, "", "\t")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -830,3 +888,26 @@ func (p *PKI) Save(opt ...Option) error {
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func encodeCertificate(c *x509.Certificate) []byte {
|
||||||
|
return pem.EncodeToMemory(&pem.Block{
|
||||||
|
Type: "CERTIFICATE",
|
||||||
|
Bytes: c.Raw,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func encodePublicKey(key crypto.PublicKey) ([]byte, error) {
|
||||||
|
block, err := pemutil.Serialize(key)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return pem.EncodeToMemory(block), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func encodePrivateKey(key crypto.PrivateKey, pass []byte) ([]byte, error) {
|
||||||
|
block, err := pemutil.Serialize(key, pemutil.WithPassword(pass))
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return pem.EncodeToMemory(block), nil
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in a new issue