github.com/webonyx/up@v0.7.4-0.20180808230834-91b94e551323/platform/aws/runtime/secrets.go (about) 1 package runtime 2 3 import ( 4 "strings" 5 6 "github.com/aws/aws-sdk-go/aws" 7 "github.com/aws/aws-sdk-go/aws/session" 8 "github.com/aws/aws-sdk-go/service/ssm" 9 "github.com/pkg/errors" 10 11 "github.com/apex/up" 12 "github.com/apex/up/internal/secret" 13 "github.com/apex/up/internal/util" 14 ) 15 16 // TODO: secret pagination 17 18 // Secrets implementation. 19 type Secrets struct { 20 client *ssm.SSM 21 name string 22 stage string 23 } 24 25 // NewSecrets returns a new secrets manager. 26 func NewSecrets(name, stage, region string) *Secrets { 27 return &Secrets{ 28 client: ssm.New(session.New(aws.NewConfig().WithRegion(region))), 29 name: name, 30 stage: stage, 31 } 32 } 33 34 // List implementation. 35 func (s *Secrets) List(decrypt bool) (v []*up.Secret, err error) { 36 res, err := s.client.DescribeParameters(&ssm.DescribeParametersInput{ 37 MaxResults: aws.Int64(50), 38 Filters: []*ssm.ParametersFilter{ 39 { 40 Key: aws.String("Name"), 41 Values: aws.StringSlice([]string{"/up/" + s.name + "/"}), 42 }, 43 }, 44 }) 45 46 if err != nil { 47 return 48 } 49 50 for _, p := range res.Parameters { 51 var value string 52 53 if *p.Type == "String" || decrypt { 54 p, err := s.client.GetParameter(&ssm.GetParameterInput{ 55 Name: p.Name, 56 WithDecryption: &decrypt, 57 }) 58 59 if err != nil { 60 return nil, errors.Wrap(err, "getting parameter") 61 } 62 63 value = *p.Parameter.Value 64 } 65 66 app, stage, name := secret.Parse(*p.Name) 67 v = append(v, &up.Secret{ 68 App: app, 69 Name: name, 70 Stage: stage, 71 Type: *p.Type, 72 Description: util.DefaultString(p.Description, ""), 73 LastModifiedUser: userFromARN(p.LastModifiedUser), 74 LastModified: *p.LastModifiedDate, 75 Value: value, 76 }) 77 } 78 79 return 80 } 81 82 // Load implementation. 83 func (s *Secrets) Load() (v []*up.Secret, err error) { 84 var token *string 85 86 for { 87 res, err := s.client.GetParametersByPath(&ssm.GetParametersByPathInput{ 88 MaxResults: aws.Int64(10), 89 Path: aws.String("/up/" + s.name + "/"), 90 WithDecryption: aws.Bool(true), 91 Recursive: aws.Bool(true), 92 NextToken: token, 93 }) 94 95 if err != nil { 96 return nil, err 97 } 98 99 for _, p := range res.Parameters { 100 app, stage, name := secret.Parse(*p.Name) 101 v = append(v, &up.Secret{ 102 App: app, 103 Name: name, 104 Stage: stage, 105 Type: *p.Type, 106 Value: *p.Value, 107 }) 108 } 109 110 token = res.NextToken 111 112 if token == nil { 113 break 114 } 115 } 116 117 return 118 } 119 120 // Add implementation. 121 func (s *Secrets) Add(key, val, desc string, clear bool) error { 122 key = s.secretName(key) 123 124 kind := "SecureString" 125 if clear { 126 kind = "String" 127 } 128 129 params := &ssm.PutParameterInput{ 130 Type: &kind, 131 Name: &key, 132 Value: &val, 133 Overwrite: aws.Bool(true), 134 } 135 136 if desc != "" { 137 params.Description = &desc 138 } 139 140 _, err := s.client.PutParameter(params) 141 return err 142 } 143 144 // Get implementation. 145 func (s *Secrets) Get(key string) (string, error) { 146 key = s.secretName(key) 147 148 res, err := s.client.GetParameter(&ssm.GetParameterInput{ 149 Name: &key, 150 WithDecryption: aws.Bool(true), 151 }) 152 153 if err != nil { 154 return "", err 155 } 156 157 return *res.Parameter.Value, nil 158 } 159 160 // Remove implementation. 161 func (s *Secrets) Remove(key string) error { 162 key = s.secretName(key) 163 164 _, err := s.client.DeleteParameter(&ssm.DeleteParameterInput{ 165 Name: &key, 166 }) 167 168 return err 169 } 170 171 // secretName returns the secret name normalized. 172 func (s *Secrets) secretName(name string) string { 173 return secret.Format(s.name, s.stage, name) 174 } 175 176 // userFromARN returns the username from ARN if present. 177 func userFromARN(arn *string) string { 178 if arn == nil { 179 return "" 180 } 181 182 p := strings.Split(*arn, "/") 183 184 if len(p) >= 2 { 185 return p[1] 186 } 187 188 return "" 189 }