package templates import ( "golang.org/x/crypto/ssh" ) // SSHTemplateVersionKey is a key that can be submitted by a client to select // the template version that will be returned by the server. var SSHTemplateVersionKey = "StepSSHTemplateVersion" // Step represents the default variables available in the CA. type Step struct { SSH StepSSH } // StepSSH holds SSH-related values for the CA. type StepSSH struct { HostKey ssh.PublicKey UserKey ssh.PublicKey HostFederatedKeys []ssh.PublicKey UserFederatedKeys []ssh.PublicKey } // DefaultSSHTemplates contains the configuration of default templates used on ssh. // Relative paths are relative to the StepPath. var DefaultSSHTemplates = SSHTemplates{ User: []Template{ { Name: "config.tpl", Type: Snippet, TemplatePath: "templates/ssh/config.tpl", Path: "~/.ssh/config", Comment: "#", }, { Name: "step_includes.tpl", Type: PrependLine, TemplatePath: "templates/ssh/step_includes.tpl", Path: "${STEPPATH}/ssh/includes", Comment: "#", }, { Name: "step_config.tpl", Type: File, TemplatePath: "templates/ssh/step_config.tpl", Path: "ssh/config", Comment: "#", }, { Name: "known_hosts.tpl", Type: File, TemplatePath: "templates/ssh/known_hosts.tpl", Path: "ssh/known_hosts", Comment: "#", }, }, Host: []Template{ { Name: "sshd_config.tpl", Type: Snippet, TemplatePath: "templates/ssh/sshd_config.tpl", Path: "/etc/ssh/sshd_config", Comment: "#", RequiredData: []string{"Certificate", "Key"}, }, { Name: "ca.tpl", Type: Snippet, TemplatePath: "templates/ssh/ca.tpl", Path: "/etc/ssh/ca.pub", Comment: "#", }, }, } // DefaultSSHTemplateData contains the data of the default templates used on ssh. var DefaultSSHTemplateData = map[string]string{ // config.tpl adds the step ssh config file. // // Note: on windows `Include C:\...` is treated as a relative path. "config.tpl": `Host * {{- if or .User.GOOS "none" | eq "windows" }} {{- if .User.StepBasePath }} Include "{{ .User.StepBasePath | replace "\\" "/" | trimPrefix "C:" }}/ssh/includes" {{- else }} Include "{{ .User.StepPath | replace "\\" "/" | trimPrefix "C:" }}/ssh/includes" {{- end }} {{- else }} {{- if .User.StepBasePath }} Include "{{.User.StepBasePath}}/ssh/includes" {{- else }} Include "{{.User.StepPath}}/ssh/includes" {{- end }} {{- end }}`, // step_includes.tpl adds the step ssh config file. // // Note: on windows `Include C:\...` is treated as a relative path. "step_includes.tpl": `{{- if or .User.GOOS "none" | eq "windows" }}Include "{{ .User.StepPath | replace "\\" "/" | trimPrefix "C:" }}/ssh/config"{{- else }}Include "{{.User.StepPath}}/ssh/config"{{- end }}`, // step_config.tpl is the step ssh config file, it includes the Match rule and // references the step known_hosts file. // // Note: on windows ProxyCommand requires the full path "step_config.tpl": `Match exec "step ssh check-host{{- if .User.Context }} --context {{ .User.Context }}{{- end }} %h" {{- if .User.User }} User {{.User.User}} {{- end }} {{- if or .User.GOOS "none" | eq "windows" }} UserKnownHostsFile "{{.User.StepPath}}\ssh\known_hosts" ProxyCommand C:\Windows\System32\cmd.exe /c step ssh proxycommand{{- if .User.Context }} --context {{ .User.Context }}{{- end }} %r %h %p {{- else }} UserKnownHostsFile "{{.User.StepPath}}/ssh/known_hosts" ProxyCommand step ssh proxycommand{{- if .User.Context }} --context {{ .User.Context }}{{- end }} %r %h %p {{- end }} `, // known_hosts.tpl authorizes the ssh hosts key "known_hosts.tpl": `@cert-authority * {{.Step.SSH.HostKey.Type}} {{.Step.SSH.HostKey.Marshal | toString | b64enc}} {{- range .Step.SSH.HostFederatedKeys}} @cert-authority * {{.Type}} {{.Marshal | toString | b64enc}} {{- end }} `, // sshd_config.tpl adds the configuration to support certificates "sshd_config.tpl": `Match all 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}} {{- range .Step.SSH.UserFederatedKeys}} {{.Type}} {{.Marshal | toString | b64enc}} {{- end }} `, } // DefaultTemplates returns the default templates. func DefaultTemplates() *Templates { sshTemplates := DefaultSSHTemplates for i, t := range sshTemplates.User { sshTemplates.User[i].TemplatePath = "" sshTemplates.User[i].Content = []byte(DefaultSSHTemplateData[t.Name]) } for i, t := range sshTemplates.Host { sshTemplates.Host[i].TemplatePath = "" sshTemplates.Host[i].Content = []byte(DefaultSSHTemplateData[t.Name]) } return &Templates{ SSH: &sshTemplates, Data: map[string]interface{}{}, } }