-
Notifications
You must be signed in to change notification settings - Fork 440
/
ssh_options.go
164 lines (141 loc) · 4.87 KB
/
ssh_options.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
package provisioner
import (
"encoding/json"
"strings"
"github.com/pkg/errors"
"go.step.sm/crypto/sshutil"
"github.com/smallstep/certificates/authority/policy"
)
// SSHCertificateOptions is an interface that returns a list of options passed when
// creating a new certificate.
type SSHCertificateOptions interface {
Options(SignSSHOptions) []sshutil.Option
}
type sshCertificateOptionsFunc func(SignSSHOptions) []sshutil.Option
func (fn sshCertificateOptionsFunc) Options(so SignSSHOptions) []sshutil.Option {
return fn(so)
}
// SSHOptions are a collection of custom options that can be added to each
// provisioner.
type SSHOptions struct {
// Template contains an SSH certificate template. It can be a JSON template
// escaped in a string or it can be also encoded in base64.
Template string `json:"template,omitempty"`
// TemplateFile points to a file containing a SSH certificate template.
TemplateFile string `json:"templateFile,omitempty"`
// TemplateData is a JSON object with variables that can be used in custom
// templates.
TemplateData json.RawMessage `json:"templateData,omitempty"`
// User contains SSH user certificate options.
User *policy.SSHUserCertificateOptions `json:"-"`
// Host contains SSH host certificate options.
Host *policy.SSHHostCertificateOptions `json:"-"`
}
// GetAllowedUserNameOptions returns the SSHNameOptions that are
// allowed when SSH User certificates are requested.
func (o *SSHOptions) GetAllowedUserNameOptions() *policy.SSHNameOptions {
if o == nil {
return nil
}
if o.User == nil {
return nil
}
return o.User.AllowedNames
}
// GetDeniedUserNameOptions returns the SSHNameOptions that are
// denied when SSH user certificates are requested.
func (o *SSHOptions) GetDeniedUserNameOptions() *policy.SSHNameOptions {
if o == nil {
return nil
}
if o.User == nil {
return nil
}
return o.User.DeniedNames
}
// GetAllowedHostNameOptions returns the SSHNameOptions that are
// allowed when SSH host certificates are requested.
func (o *SSHOptions) GetAllowedHostNameOptions() *policy.SSHNameOptions {
if o == nil {
return nil
}
if o.Host == nil {
return nil
}
return o.Host.AllowedNames
}
// GetDeniedHostNameOptions returns the SSHNameOptions that are
// denied when SSH host certificates are requested.
func (o *SSHOptions) GetDeniedHostNameOptions() *policy.SSHNameOptions {
if o == nil {
return nil
}
if o.Host == nil {
return nil
}
return o.Host.DeniedNames
}
// HasTemplate returns true if a template is defined in the provisioner options.
func (o *SSHOptions) HasTemplate() bool {
return o != nil && (o.Template != "" || o.TemplateFile != "")
}
// TemplateSSHOptions generates a SSHCertificateOptions with the template and
// data defined in the ProvisionerOptions, the provisioner generated data, and
// the user data provided in the request. If no template has been provided,
// x509util.DefaultLeafTemplate will be used.
func TemplateSSHOptions(o *Options, data sshutil.TemplateData) (SSHCertificateOptions, error) {
return CustomSSHTemplateOptions(o, data, sshutil.DefaultTemplate)
}
// CustomSSHTemplateOptions generates a CertificateOptions with the template, data
// defined in the ProvisionerOptions, the provisioner generated data and the
// user data provided in the request. If no template has been provided in the
// ProvisionerOptions, the given template will be used.
func CustomSSHTemplateOptions(o *Options, data sshutil.TemplateData, defaultTemplate string) (SSHCertificateOptions, error) {
opts := o.GetSSHOptions()
if data == nil {
data = sshutil.NewTemplateData()
}
if opts != nil {
// Add template data if any.
if len(opts.TemplateData) > 0 && string(opts.TemplateData) != "null" {
if err := json.Unmarshal(opts.TemplateData, &data); err != nil {
return nil, errors.Wrap(err, "error unmarshaling template data")
}
}
}
return sshCertificateOptionsFunc(func(so SignSSHOptions) []sshutil.Option {
// We're not provided user data without custom templates.
if !opts.HasTemplate() {
return []sshutil.Option{
sshutil.WithTemplate(defaultTemplate, data),
}
}
// Add user provided data.
if len(so.TemplateData) > 0 {
userObject := make(map[string]interface{})
if err := json.Unmarshal(so.TemplateData, &userObject); err != nil {
data.SetUserData(map[string]interface{}{})
} else {
data.SetUserData(userObject)
}
}
// Load a template from a file if Template is not defined.
if opts.Template == "" && opts.TemplateFile != "" {
return []sshutil.Option{
sshutil.WithTemplateFile(opts.TemplateFile, data),
}
}
// Load a template from the Template fields
// 1. As a JSON in a string.
template := strings.TrimSpace(opts.Template)
if strings.HasPrefix(template, "{") {
return []sshutil.Option{
sshutil.WithTemplate(template, data),
}
}
// 2. As a base64 encoded JSON.
return []sshutil.Option{
sshutil.WithTemplateBase64(template, data),
}
}), nil
}