This repository has been archived by the owner on Mar 24, 2022. It is now read-only.
/
ssm.go
128 lines (118 loc) · 3.54 KB
/
ssm.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
package ssm
import (
"bytes"
"strings"
"text/template"
"code.cloudfoundry.org/lager"
"github.com/aws/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go/aws/awserr"
"github.com/aws/aws-sdk-go/service/ssm"
"github.com/aws/aws-sdk-go/service/ssm/ssmiface"
varTemplate "github.com/cloudfoundry/bosh-cli/director/template"
)
type Ssm struct {
log lager.Logger
api ssmiface.SSMAPI
TeamName string
PipelineName string
SecretTemplates []*template.Template
}
func NewSsm(log lager.Logger, api ssmiface.SSMAPI, teamName string, pipelineName string, secretTemplates []*template.Template) *Ssm {
return &Ssm{
log: log,
api: api,
TeamName: teamName,
PipelineName: pipelineName,
SecretTemplates: secretTemplates,
}
}
func (s *Ssm) transformSecret(nameTemplate *template.Template, secret string) (string, error) {
var buf bytes.Buffer
err := nameTemplate.Execute(&buf, &SsmSecret{
Team: s.TeamName,
Pipeline: s.PipelineName,
Secret: secret,
})
return buf.String(), err
}
func (s *Ssm) Get(varDef varTemplate.VariableDefinition) (interface{}, bool, error) {
for _, st := range s.SecretTemplates {
// Try to get the parameter as string value
parameter, err := s.transformSecret(st, varDef.Name)
if err != nil {
s.log.Error("failed-to-build-ssm-parameter-path-from-secret", err, lager.Data{
"template": st.Name(),
"secret": varDef.Name,
})
return nil, false, err
}
// If pipeline name is empty, double slashes may be present in the parameter name
if strings.Contains(parameter, "//") {
continue
}
value, found, err := s.getParameterByName(parameter)
if err != nil {
s.log.Error("failed-to-get-ssm-parameter-by-name", err, lager.Data{
"template": st.Name(),
"secret": varDef.Name,
"parameter": parameter,
})
return nil, false, err
}
if found {
return value, true, nil
}
// // Paramter may exist as a complex value so try again using paramter name as root path
value, found, err = s.getParameterByPath(parameter)
if err != nil {
s.log.Error("failed-to-get-ssm-parameter-by-path", err, lager.Data{
"template": st.Name(),
"secret": varDef.Name,
"parameter": parameter,
})
return nil, false, err
}
if found {
return value, true, nil
}
}
return nil, false, nil
}
func (s *Ssm) getParameterByName(name string) (interface{}, bool, error) {
param, err := s.api.GetParameter(&ssm.GetParameterInput{
Name: &name,
WithDecryption: aws.Bool(true),
})
if err == nil {
return *param.Parameter.Value, true, nil
} else if errObj, ok := err.(awserr.Error); ok && errObj.Code() == ssm.ErrCodeParameterNotFound {
return nil, false, nil
}
return nil, false, err
}
func (s *Ssm) getParameterByPath(path string) (interface{}, bool, error) {
path = strings.TrimRight(path, "/")
if path == "" {
path = "/"
}
value := make(map[interface{}]interface{})
pathQuery := &ssm.GetParametersByPathInput{}
pathQuery = pathQuery.SetPath(path).SetRecursive(true).SetWithDecryption(true).SetMaxResults(10)
err := s.api.GetParametersByPathPages(pathQuery, func(page *ssm.GetParametersByPathOutput, lastPage bool) bool {
for _, param := range page.Parameters {
value[(*param.Name)[len(path)+1:]] = *param.Value
}
return true
})
if err != nil {
return nil, false, err
}
if len(value) == 0 {
return nil, false, nil
}
return value, true, nil
}
func (s *Ssm) List() ([]varTemplate.VariableDefinition, error) {
// not implemented, see vault implementation
return []varTemplate.VariableDefinition{}, nil
}