Add first version of ssh templates.

This commit is contained in:
Mariano Cano 2019-10-11 12:49:09 -07:00
parent 74c1b4e771
commit 829a86a5d7
2 changed files with 116 additions and 3 deletions

View file

@ -434,6 +434,7 @@ func (p *PKI) GenerateConfig(opt ...Option) (*authority.Config, error) {
Renegotiation: x509util.DefaultTLSRenegotiation, Renegotiation: x509util.DefaultTLSRenegotiation,
CipherSuites: x509util.DefaultTLSCipherSuites, CipherSuites: x509util.DefaultTLSCipherSuites,
}, },
Templates: p.getTemplates(),
} }
if p.enableSSH { if p.enableSSH {
enableSSHCA := true enableSSHCA := true
@ -461,6 +462,7 @@ func (p *PKI) GenerateConfig(opt ...Option) (*authority.Config, error) {
func (p *PKI) Save(opt ...Option) error { func (p *PKI) Save(opt ...Option) error {
p.tellPKI() p.tellPKI()
// Generate and write ca.json
config, err := p.GenerateConfig(opt...) config, err := p.GenerateConfig(opt...)
if err != nil { if err != nil {
return err return err
@ -489,6 +491,7 @@ func (p *PKI) Save(opt ...Option) error {
} }
} }
// Generate and write defaults.json
defaults := &caDefaults{ defaults := &caDefaults{
Root: p.root, Root: p.root,
CAConfig: p.config, CAConfig: p.config,
@ -503,11 +506,20 @@ func (p *PKI) Save(opt ...Option) error {
return errs.FileError(err, p.defaults) return errs.FileError(err, p.defaults)
} }
// Generate and write templates
if err := generateTemplates(config.Templates); err != nil {
return err
}
if config.DB != nil {
ui.PrintSelected("Database folder", config.DB.DataSource)
}
if config.Templates != nil {
ui.PrintSelected("Templates folder", GetTemplatesPath())
}
ui.PrintSelected("Default configuration", p.defaults) ui.PrintSelected("Default configuration", p.defaults)
ui.PrintSelected("Certificate Authority configuration", p.config) ui.PrintSelected("Certificate Authority configuration", p.config)
if config.DB != nil {
ui.PrintSelected("Database", config.DB.DataSource)
}
ui.Println() ui.Println()
ui.Println("Your PKI is ready to go. To generate certificates for individual services see 'step help ca'.") ui.Println("Your PKI is ready to go. To generate certificates for individual services see 'step help ca'.")

101
pki/templates.go Normal file
View file

@ -0,0 +1,101 @@
package pki
import (
"os"
"path/filepath"
"github.com/smallstep/cli/utils"
"github.com/pkg/errors"
"github.com/smallstep/certificates/templates"
"github.com/smallstep/cli/errs"
)
// sshTemplates contains the configuration of default templates used on ssh.
var sshTemplates = &templates.SSHTemplates{
User: []templates.Template{
{Name: "include.tpl", Type: templates.Snippet, TemplatePath: "ssh/include.tpl", Path: "~/.ssh/config", Comment: "#"},
{Name: "config.tpl", Type: templates.File, TemplatePath: "ssh/config.tpl", Path: "ssh/config", Comment: "#"},
{Name: "known_hosts.tpl", Type: templates.File, TemplatePath: "ssh/known_hosts.tpl", Path: "ssh/known_hosts", Comment: "#"},
},
Host: []templates.Template{
{Name: "sshd_config.tpl", Type: templates.Snippet, TemplatePath: "ssh/sshd_config.tpl", Path: "/etc/ssh/sshd_config", Comment: "#"},
{Name: "ca.tpl", Type: templates.Snippet, TemplatePath: "ssh/ca.tpl", Path: "/etc/ssh/ca.pub", Comment: "#"},
},
}
// sshTemplateData contains the data of the default templates used on ssh.
var sshTemplateData = map[string]string{
// include.tpl adds the step ssh config file
"include.tpl": `Host *
Include {{.User.StepPath}}/ssh/config`,
// config.tpl is the step ssh config file, it includes the Match rule
// and references the step known_hosts file
"config.tpl": `Match exec "step ssh check-host %h"
ForwardAgent yes
UserKnownHostsFile {{.User.StepPath}}/config/ssh/known_hosts`,
// known_hosts.tpl authorizes the ssh hosst key
"known_hosts.tpl": "@cert-authority * {{.Step.SSH.HostKey.Type}} {{.Step.SSH.HostKey.Marshal | toString | b64enc}}",
// sshd_config.tpl adds the configuration to support certificates
"sshd_config.tpl": `TrustedUserCAKeys /etc/ssh/ca.pub
HostCertificate /etc/ssh/{{.User.Certificate}}
HostKey /etc/ssh/{{.User.Key}}`,
// ca.tpl contains the public key used to authorized clients
"ca.tpl": "{{.Step.SSH.UserKey.Type}} {{.Step.SSH.UserKey.Marshal | toString | b64enc}}",
}
// getTemplates returns all the templates enabled
func (p *PKI) getTemplates() *templates.Templates {
if !p.enableSSH {
return nil
}
return &templates.Templates{
SSH: sshTemplates,
Data: map[string]interface{}{},
}
}
// generateTemplates generates given templates.
func generateTemplates(t *templates.Templates) error {
if t == nil {
return nil
}
base := GetTemplatesPath()
// Generate SSH templates
if t.SSH != nil {
// all ssh templates are under ssh:
sshDir := filepath.Join(base, "ssh")
if _, err := os.Stat(sshDir); os.IsNotExist(err) {
if err = os.MkdirAll(sshDir, 0700); err != nil {
return errs.FileError(err, sshDir)
}
}
// Create all templates
for _, t := range t.SSH.User {
data, ok := sshTemplateData[t.Name]
if !ok {
return errors.Errorf("template %s does not exists", t.Name)
}
if err := utils.WriteFile(filepath.Join(base, t.TemplatePath), []byte(data), 0644); err != nil {
return err
}
}
for _, t := range t.SSH.Host {
data, ok := sshTemplateData[t.Name]
if !ok {
return errors.Errorf("template %s does not exists", t.Name)
}
if err := utils.WriteFile(filepath.Join(base, t.TemplatePath), []byte(data), 0644); err != nil {
return err
}
}
}
return nil
}