├── .gitignore ├── .travis.yml ├── go.mod ├── .goreleaser.yml ├── main.go ├── envinjector ├── trace.go ├── inject.go ├── secrets_manager.go ├── services.go ├── meta_config.go └── ssm.go ├── LICENSE ├── go.sum └── README.md /.gitignore: -------------------------------------------------------------------------------- 1 | .idea 2 | *.iml 3 | 4 | env-injector 5 | vendor 6 | dist 7 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: go 2 | go: 3 | - 1.x 4 | before_install: 5 | - go get -v github.com/aws/aws-sdk-go 6 | script: 7 | - go test 8 | after_success: 9 | - test -n "$TRAVIS_TAG" && curl -sL https://git.io/goreleaser | bash -------------------------------------------------------------------------------- /go.mod: -------------------------------------------------------------------------------- 1 | module github.com/okzk/env-injector 2 | 3 | go 1.19 4 | 5 | require ( 6 | github.com/aws/aws-sdk-go v1.44.108 7 | gopkg.in/yaml.v2 v2.4.0 8 | ) 9 | 10 | require github.com/jmespath/go-jmespath v0.4.0 // indirect 11 | -------------------------------------------------------------------------------- /.goreleaser.yml: -------------------------------------------------------------------------------- 1 | builds: 2 | - env: 3 | - CGO_ENABLED=0 4 | goos: 5 | - windows 6 | - darwin 7 | - linux 8 | goarch: 9 | - amd64 10 | - 386 11 | ignore: 12 | - goos: darwin 13 | goarch: 386 14 | archive: 15 | format: tar.gz 16 | files: 17 | - README.md 18 | - LICENSE 19 | release: 20 | github: 21 | owner: okzk 22 | name: env-injector 23 | -------------------------------------------------------------------------------- /main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "github.com/okzk/env-injector/envinjector" 5 | "log" 6 | "os" 7 | "os/exec" 8 | "syscall" 9 | ) 10 | 11 | func main() { 12 | envinjector.InjectEnviron() 13 | 14 | args := os.Args 15 | if len(args) <= 1 { 16 | log.Fatal("missing command") 17 | } 18 | 19 | path, err := exec.LookPath(args[1]) 20 | if err != nil { 21 | log.Fatal(err) 22 | } 23 | err = syscall.Exec(path, args[1:], os.Environ()) 24 | if err != nil { 25 | log.Fatal(err) 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /envinjector/trace.go: -------------------------------------------------------------------------------- 1 | package envinjector 2 | 3 | import ( 4 | "log" 5 | "os" 6 | ) 7 | 8 | var verbose = os.Getenv("ENV_INJECTOR_VERBOSE") == "1" 9 | var logger = log.New(os.Stderr, "[env-injector] ", 0) 10 | 11 | // ConfigLogger calls the given function with internal logger. 12 | func ConfigLogger(f func(logger *log.Logger)) { 13 | f(logger) 14 | } 15 | 16 | func trace(v ...interface{}) { 17 | if verbose { 18 | logger.Println(v...) 19 | } 20 | } 21 | 22 | func tracef(format string, v ...interface{}) { 23 | if verbose { 24 | logger.Printf(format, v...) 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /envinjector/inject.go: -------------------------------------------------------------------------------- 1 | package envinjector 2 | 3 | import "os" 4 | 5 | // InjectEnviron injects environment variables from AWS Parameter Store and/or SecretsManager 6 | func InjectEnviron() { 7 | if path := os.Getenv("ENV_INJECTOR_META_CONFIG"); path != "" { 8 | injectEnvironViaMetaConfig(path) 9 | } else { 10 | trace("no meta config path specified, skipping injection via meta config") 11 | } 12 | 13 | if name := os.Getenv("ENV_INJECTOR_SECRET_NAME"); name != "" { 14 | injectEnvironSecretManager(name, noop) 15 | } else { 16 | trace("no secret name specified, skipping injection by SecretsManager") 17 | } 18 | 19 | if path := os.Getenv("ENV_INJECTOR_PATH"); path != "" { 20 | injectEnvironByPath(path, noop) 21 | } else { 22 | trace("no parameter path specified, skipping injection by path") 23 | } 24 | 25 | if prefix := os.Getenv("ENV_INJECTOR_PREFIX"); prefix != "" { 26 | injectEnvironByPrefix(prefix) 27 | } else { 28 | trace("no parameter prefix specified, skipping injection by prefix") 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /envinjector/secrets_manager.go: -------------------------------------------------------------------------------- 1 | package envinjector 2 | 3 | import ( 4 | "encoding/json" 5 | "fmt" 6 | "github.com/aws/aws-sdk-go/aws" 7 | "github.com/aws/aws-sdk-go/service/secretsmanager" 8 | "os" 9 | ) 10 | 11 | func injectEnvironSecretManager(name string, decorator envKeyDecorator) { 12 | tracef("secret name: %s", name) 13 | 14 | svc := getService().secretsManager 15 | ret, err := svc.GetSecretValue(&secretsmanager.GetSecretValueInput{ 16 | SecretId: aws.String(name), 17 | }) 18 | if err != nil { 19 | logger.Fatalf("secretsmanager:GetSecretValue failed. (name: %s)\n %v", name, err) 20 | } 21 | secrets := make(map[string]interface{}) 22 | err = json.Unmarshal([]byte(aws.StringValue(ret.SecretString)), &secrets) 23 | if err != nil { 24 | logger.Fatalf("secretsmanager:GetSecretValue returns invalid json. (name: %s)\n %v", name, err) 25 | } 26 | for key, val := range secrets { 27 | key = decorator.decorate(key) 28 | if os.Getenv(key) == "" { 29 | os.Setenv(key, fmt.Sprintf("%v", val)) 30 | tracef("env injected: %s", key) 31 | } 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2017 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /envinjector/services.go: -------------------------------------------------------------------------------- 1 | package envinjector 2 | 3 | import ( 4 | "github.com/aws/aws-sdk-go/aws" 5 | "github.com/aws/aws-sdk-go/aws/credentials/stscreds" 6 | "github.com/aws/aws-sdk-go/aws/ec2metadata" 7 | "github.com/aws/aws-sdk-go/aws/session" 8 | "github.com/aws/aws-sdk-go/service/secretsmanager" 9 | "github.com/aws/aws-sdk-go/service/ssm" 10 | "os" 11 | ) 12 | 13 | // For lazy initialization 14 | var services *awsServices 15 | 16 | type awsServices struct { 17 | ssm *ssm.SSM 18 | secretsManager *secretsmanager.SecretsManager 19 | } 20 | 21 | func newAWSServices() *awsServices { 22 | sess, err := session.NewSessionWithOptions(session.Options{ 23 | SharedConfigState: session.SharedConfigEnable, 24 | }) 25 | if err != nil { 26 | logger.Fatalf("failed to create a new session.\n %v", err) 27 | } 28 | if aws.StringValue(sess.Config.Region) == "" { 29 | trace("no explicit region configurations. So now retrieving ec2metadata...") 30 | region, err := ec2metadata.New(sess).Region() 31 | if err != nil { 32 | trace(err) 33 | logger.Fatalf("could not find region configurations") 34 | } 35 | sess.Config.Region = aws.String(region) 36 | } 37 | 38 | if arn := os.Getenv("ENV_INJECTOR_ASSUME_ROLE_ARN"); arn != "" { 39 | creds := stscreds.NewCredentials(sess, arn) 40 | return &awsServices{ 41 | ssm: ssm.New(sess, &aws.Config{Credentials: creds}), 42 | secretsManager: secretsmanager.New(sess, &aws.Config{Credentials: creds}), 43 | } 44 | } 45 | return &awsServices{ 46 | ssm: ssm.New(sess), 47 | secretsManager: secretsmanager.New(sess), 48 | } 49 | } 50 | 51 | // Initialize services lazily, and return it. 52 | func getService() *awsServices { 53 | if services == nil { 54 | services = newAWSServices() 55 | } 56 | return services 57 | } 58 | -------------------------------------------------------------------------------- /envinjector/meta_config.go: -------------------------------------------------------------------------------- 1 | package envinjector 2 | 3 | import ( 4 | "github.com/aws/aws-sdk-go/aws" 5 | "github.com/aws/aws-sdk-go/service/ssm" 6 | "gopkg.in/yaml.v2" 7 | "log" 8 | "strings" 9 | ) 10 | 11 | type envKeyDecorator interface { 12 | decorate(key string) string 13 | } 14 | 15 | type noopKeyDecorator struct{} 16 | 17 | func (*noopKeyDecorator) decorate(key string) string { return key } 18 | 19 | var noop = &noopKeyDecorator{} 20 | 21 | type metaConfig struct { 22 | SecretName string `yaml:"secret_name"` 23 | ParameterStorePath string `yaml:"parameter_store_path"` 24 | 25 | EnvPrefix string `yaml:"env_prefix"` 26 | Capitalize bool `yaml:"capitalize"` 27 | } 28 | 29 | func (m *metaConfig) decorate(key string) string { 30 | if m.EnvPrefix != "" { 31 | key = m.EnvPrefix + "_" + key 32 | } 33 | if m.Capitalize { 34 | return strings.ToUpper(key) 35 | } 36 | 37 | return key 38 | } 39 | 40 | func (m *metaConfig) injectEnviron() { 41 | if m.SecretName != "" { 42 | injectEnvironSecretManager(m.SecretName, m) 43 | } 44 | if m.ParameterStorePath != "" { 45 | injectEnvironByPath(m.ParameterStorePath, m) 46 | } 47 | } 48 | 49 | func injectEnvironViaMetaConfig(path string) { 50 | svc := getService().ssm 51 | result, err := svc.GetParameter(&ssm.GetParameterInput{ 52 | Name: aws.String(path), 53 | WithDecryption: aws.Bool(true), 54 | }) 55 | if err != nil { 56 | logger.Fatalf("ssm:GetParameter failed. (path: %s)\n %v", path, err) 57 | } 58 | 59 | configs := make([]*metaConfig, 0) 60 | err = yaml.Unmarshal([]byte(aws.StringValue(result.Parameter.Value)), &configs) 61 | if err != nil { 62 | log.Fatalf("ssm:GetParameter returns invalid yaml. (path: %s)\n %v", path, err) 63 | } 64 | 65 | for _, config := range configs { 66 | config.injectEnviron() 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /go.sum: -------------------------------------------------------------------------------- 1 | github.com/aws/aws-sdk-go v1.44.108 h1:L8N9GmP9UYDNqBtJO6OC4zSuEkQxAR770VkbRXAUmRk= 2 | github.com/aws/aws-sdk-go v1.44.108/go.mod h1:y4AeaBuwd2Lk+GepC1E9v0qOiTws0MIWAX4oIKwKHZo= 3 | github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8= 4 | github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= 5 | github.com/jmespath/go-jmespath v0.4.0 h1:BEgLn5cpjn8UN1mAw4NjwDrS35OdebyEtFe+9YPoQUg= 6 | github.com/jmespath/go-jmespath v0.4.0/go.mod h1:T8mJZnbsbmF+m6zOOFylbeCJqk5+pHWvzYPziyZiYoo= 7 | github.com/jmespath/go-jmespath/internal/testify v1.5.1 h1:shLQSRRSCCPj3f2gpwzGwWFoC7ycTf1rcQZHOlsJ6N8= 8 | github.com/jmespath/go-jmespath/internal/testify v1.5.1/go.mod h1:L3OGu8Wl2/fWfCI6z80xFu9LTZmf1ZRjMHUOPmWr69U= 9 | github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= 10 | github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= 11 | github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= 12 | github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= 13 | golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= 14 | golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 15 | golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 16 | golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= 17 | golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= 18 | golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= 19 | gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= 20 | gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= 21 | gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= 22 | gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= 23 | gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= 24 | -------------------------------------------------------------------------------- /envinjector/ssm.go: -------------------------------------------------------------------------------- 1 | package envinjector 2 | 3 | import ( 4 | "github.com/aws/aws-sdk-go/aws" 5 | "github.com/aws/aws-sdk-go/service/ssm" 6 | "os" 7 | "path/filepath" 8 | "strings" 9 | ) 10 | 11 | func injectEnvironByPath(path string, decorator envKeyDecorator) { 12 | tracef("parameter path: %s", path) 13 | 14 | svc := getService().ssm 15 | var nextToken *string 16 | for { 17 | result, err := svc.GetParametersByPath(&ssm.GetParametersByPathInput{ 18 | Path: aws.String(path), 19 | WithDecryption: aws.Bool(true), 20 | NextToken: nextToken, 21 | }) 22 | if err != nil { 23 | logger.Fatalf("ssm:GetParametersByPath failed. (path: %s)\n %v", path, err) 24 | } 25 | 26 | for _, param := range result.Parameters { 27 | key, err := filepath.Rel(path, aws.StringValue(param.Name)) 28 | if err != nil { 29 | trace(err) 30 | continue 31 | } 32 | key = decorator.decorate(key) 33 | if os.Getenv(key) == "" { 34 | os.Setenv(key, aws.StringValue(param.Value)) 35 | tracef("env injected: %s", key) 36 | } 37 | } 38 | nextToken = result.NextToken 39 | if nextToken == nil || aws.StringValue(nextToken) == "" { 40 | break 41 | } 42 | } 43 | } 44 | 45 | func injectEnvironByPrefix(prefix string) { 46 | tracef("parameter prefix: %s", prefix) 47 | if !strings.HasSuffix(prefix, ".") { 48 | prefix += "." 49 | } 50 | 51 | names := []*string{} 52 | for _, env := range os.Environ() { 53 | parts := strings.SplitN(env, "=", 2) 54 | if len(parts) == 2 && parts[1] == "" { 55 | names = append(names, aws.String(prefix+parts[0])) 56 | } 57 | } 58 | if len(names) == 0 { 59 | trace("nothing to be injected by prefix") 60 | return 61 | } 62 | 63 | svc := getService().ssm 64 | 65 | // 'GetParameters' fails entirely when any one of parameters is not permitted to get. 66 | // So call 'GetParameters' one by one. 67 | for _, n := range names { 68 | result, err := svc.GetParameters(&ssm.GetParametersInput{ 69 | Names: []*string{n}, 70 | WithDecryption: aws.Bool(true), 71 | }) 72 | if err != nil { 73 | tracef("failed to get: %s", *n) 74 | trace(err) 75 | continue 76 | } 77 | 78 | for _, key := range result.InvalidParameters { 79 | tracef("invalid parameter: %s", aws.StringValue(key)) 80 | } 81 | for _, param := range result.Parameters { 82 | key := strings.TrimPrefix(aws.StringValue(param.Name), prefix) 83 | os.Setenv(key, aws.StringValue(param.Value)) 84 | tracef("env injected: %s", key) 85 | } 86 | } 87 | } 88 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # env-injector 2 | 3 | A simple tool to inject credentials into environment variables from AWS Secrets Manager 4 | and/or Systems Manager Parameter Store. 5 | 6 | ## Install 7 | 8 | Download from [releases](https://github.com/okzk/env-injector/releases). 9 | 10 | ## How to use 11 | 12 | ### Using meta config 13 | 14 | 15 | ``` bash 16 | # When your secrets manager and parameter store are configured as below, 17 | $ aws secretsmanager get-secret-value --secret-id prd/db1 --query SecretString --output text 18 | {"user":"alice","password":"foo"} 19 | $ aws secretsmanager get-secret-value --secret-id prd/db2 --query SecretString --output text 20 | {"user":"bob","password":"bar"} 21 | $ aws ssm get-parameters-by-path --with-decryption --path /prod/wap 22 | { 23 | "Parameters": [ 24 | { 25 | "Type": "SecureString", 26 | "Name": "/prod/wap/SOME_OTHER_CONFIG", 27 | "Value": "hoge" 28 | } 29 | ] 30 | } 31 | 32 | # And meta config yaml is stored as below, 33 | $ aws ssm get-parameter --name /meta/prd/wap --query Parameter.Value --output text 34 | - secret_name: prd/db1 35 | env_prefix: db1 36 | capitalize: true 37 | - secret_name: prd/db2 38 | env_prefix: db2 39 | capitalize: true 40 | - parameter_store_path: /prod/wap 41 | 42 | 43 | # Then specify meta config, 44 | $ export ENV_INJECTOR_META_CONFIG=/meta/prd/wap 45 | 46 | # and exec your command via env-injector. 47 | $ env-injector env 48 | DB1_USER=alice 49 | DB1_PASSWORD=foo 50 | DB2_USER=bob 51 | DB2_PASSWORD=var 52 | SOME_OTHER_CONFIG=hoge 53 | ``` 54 | 55 | ### Injecting form Secrets Manages 56 | 57 | ``` bash 58 | # When your secrets manager is configured as below, 59 | $ aws secretsmanager get-secret-value --secret-id prd/db --query SecretString --output text 60 | {"DB_USER":"scott","DB_PASSWORD":"tiger"} 61 | 62 | # And specify your secret name 63 | $ export ENV_INJECTOR_SECRET_NAME=prd/db 64 | 65 | # Then exec your command via env-injector. 66 | $ env-injector env | grep DB_ 67 | DB_USER=scott 68 | DB_PASSWORD=tiger 69 | ``` 70 | 71 | Required IAM role policy is as follows: 72 | 73 | ```json 74 | { 75 | "Version": "2012-10-17", 76 | "Statement": [ 77 | { 78 | "Effect": "Allow", 79 | "Action": [ 80 | "secretsmanager:GetSecretValue" 81 | ], 82 | "Resource": [ 83 | "arn:aws:secretsmanager:ap-northeast-1:123456789012:secret:prd/db-*" 84 | ] 85 | } 86 | ] 87 | } 88 | ``` 89 | 90 | 91 | ### Injecting form Parameter Store 92 | You can use hierarchical parameters and/or grouped parameters. 93 | 94 | #### Injecting hierarchical parameters 95 | 96 | ``` bash 97 | # When your parameter store is configured as below, 98 | $ aws ssm get-parameters-by-path --with-decryption --path /prod/wap 99 | { 100 | "Parameters": [ 101 | { 102 | "Type": "String", 103 | "Name": "/prod/wap/DB_USER", 104 | "Value": "scott" 105 | }, 106 | { 107 | "Type": "SecureString", 108 | "Name": "/prod/wap/DB_PASSWORD", 109 | "Value": "tiger" 110 | } 111 | ] 112 | } 113 | 114 | # And specify parameter name path 115 | $ export ENV_INJECTOR_PATH=/prod/wap 116 | 117 | # Then exec your command via env-injector. 118 | $ env-injector env | grep DB_ 119 | DB_USER=scott 120 | DB_PASSWORD=tiger 121 | ``` 122 | 123 | Required IAM role policy is as follows: 124 | 125 | ```json 126 | { 127 | "Version": "2012-10-17", 128 | "Statement": [ 129 | { 130 | "Effect": "Allow", 131 | "Action": [ 132 | "ssm:GetParametersByPath" 133 | ], 134 | "Resource": [ 135 | "arn:aws:ssm:ap-northeast-1:123456789012:parameter/prod/wap" 136 | ] 137 | } 138 | ] 139 | } 140 | ``` 141 | 142 | 143 | #### Injecting grouped parameters 144 | 145 | ``` bash 146 | # When your parameter store is configured as below, 147 | $ aws ssm get-parameters --with-decryption --names prod.wap.DB_USER prod.wap.DB_PASSWORD 148 | { 149 | "InvalidParameters": [], 150 | "Parameters": [ 151 | { 152 | "Type": "String", 153 | "Name": "prod.wap.DB_USER", 154 | "Value": "scott" 155 | }, 156 | { 157 | "Type": "SecureString", 158 | "Name": "prod.wap.DB_PASSWORD", 159 | "Value": "tiger" 160 | } 161 | ] 162 | } 163 | 164 | 165 | # Set empty environment valiables. 166 | $ export DB_USER= 167 | $ export DB_PASSWORD= 168 | 169 | # And specify parameter name prefix. 170 | $ export ENV_INJECTOR_PREFIX=prod.wap 171 | 172 | # Then exec your command via env-injector. 173 | $ env-injector env | grep DB_ 174 | DB_USER=scott 175 | DB_PASSWORD=tiger 176 | ``` 177 | 178 | Required IAM role policy is as follows: 179 | 180 | ```json 181 | { 182 | "Version": "2012-10-17", 183 | "Statement": [ 184 | { 185 | "Effect": "Allow", 186 | "Action": [ 187 | "ssm:GetParameters" 188 | ], 189 | "Resource": [ 190 | "arn:aws:ssm:ap-northeast-1:123456789012:parameter/prod.wap.*" 191 | ] 192 | } 193 | ] 194 | } 195 | ``` 196 | 197 | ### 198 | 199 | ## DEBUG 200 | 201 | Set `ENV_INJECTOR_VERBOSE=1` 202 | --------------------------------------------------------------------------------