is2-aws-ssm-env 0.1.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,322 @@
1
+ [![Build Status](https://travis-ci.org/sonodar/aws-ssm-env-ruby.svg?branch=master)](https://travis-ci.org/sonodar/aws-ssm-env-ruby)
2
+ [![Coverage Status](https://coveralls.io/repos/github/sonodar/aws-ssm-env-ruby/badge.svg?branch=master)](https://coveralls.io/github/sonodar/aws-ssm-env-ruby?branch=master)
3
+ [![Gem Version](https://badge.fury.io/rb/aws-ssm-env.svg)](https://badge.fury.io/rb/aws-ssm-env)
4
+
5
+ # aws-ssm-env
6
+
7
+ AWS EC2 Parameter Storeから取得したパラメータを環境変数として設定します。
8
+
9
+ デフォルトでは、パラメータ名の最後の階層が環境変数名として設定されます。
10
+
11
+ 例えば、`/staging/secure/DB_PASSWORD`というパラメータ名であれば、`ENV['DB_PASSWORD']`にパラメータ値が設定されます。
12
+ この環境変数のネーミングはオプションでカスタマイズ可能です。(後述)
13
+
14
+ ## Installation
15
+
16
+ このgemはRuby2.2から2.5まででテストされています。
17
+
18
+ ```
19
+ gem install aws-ssm-env
20
+ ```
21
+
22
+ ### Rails
23
+
24
+ ```ruby
25
+ # Gemfile
26
+ gem 'aws-ssm-env', group: :aws
27
+ ```
28
+
29
+ ```ruby
30
+ # config/application.rb
31
+ if defined?(AwsSsmEnv)
32
+ AwsSsmEnv.load(path: "/myapp/#{ENV['RAILS_ENV']}", recursive: true)
33
+ end
34
+ ```
35
+
36
+ ### Other ruby program
37
+
38
+ ```ruby
39
+ require 'aws-ssm-env'
40
+ AwsSsmEnv.load!(begins_with: "myapp.#{ENV['RACK_ENV']}.")
41
+ ```
42
+
43
+ ## Quick Start
44
+
45
+ 事前にAWS EC2 Parameter Storeにパラメータを登録しておく必要があります。
46
+
47
+ ```shell
48
+ # 例) /myservice/staging/RDS_PASSWORDをSecureStringで登録
49
+ aws ssm --region ap-northeast-1 put-parameter \
50
+ --name /myservice/staging/RDS_PASSWORD \
51
+ --type SecureString --value <secret value>
52
+ ```
53
+
54
+ AWSの認証情報を設定します。例えば、以下のように環境変数を利用したり、
55
+
56
+ ```shell
57
+ export AWS_ACCESS_KEY_ID=YOURACCESSKEYID
58
+ export AWS_SECRET_ACCESS_KEY=YOURSECRETKEY
59
+ bundle exec rails start
60
+ ```
61
+
62
+ 引数で`ssm_client_args`を渡したり、
63
+
64
+ ```ruby
65
+ AwsSsmEnv.load(
66
+ fetch: "/myservice/#{ENV['RAILS_ENV']}",
67
+ ssm_client_args: {
68
+ access_key_id: 'ACCESS_KEY_ID',
69
+ secret_access_key: 'SECRET_ACCESS_KEY',
70
+ region: 'ap-northeast-1',
71
+ }
72
+ )
73
+ ```
74
+
75
+ `Aws.config`を利用することもできます。
76
+
77
+ ```ruby
78
+
79
+ if defined?(AwsSsmEnv)
80
+ AWS.config({
81
+ access_key_id: 'ACCESS_KEY_ID',
82
+ secret_access_key: 'SECRET_ACCESS_KEY',
83
+ region: 'ap-northeast-1',
84
+ })
85
+ AwsSsmEnv.load(path: "/myservice/#{ENV['RAILS_ENV']}")
86
+ end
87
+ ```
88
+
89
+ 詳細はaws-sdkのドキュメントを参照してください。
90
+
91
+ ## Develop
92
+
93
+ ### Unit test
94
+
95
+ ```shell
96
+ bundle exec rspec
97
+ bundle exec rubocop
98
+ ```
99
+
100
+ ### Integration test
101
+
102
+ ```shell
103
+ export AWS_ACCESS_KEY_ID=xxxx
104
+ export AWS_SECRET_ACCESS_KEY=xxxx
105
+ export AWS_REGION=xxxx
106
+ bundle exec rspec --tag integration
107
+ ```
108
+
109
+ IAMユーザには以下の認可ポリシーが必要です。
110
+
111
+ ```json
112
+ {
113
+ "Version": "2012-10-17",
114
+ "Statement": [
115
+ {
116
+ "Sid": "",
117
+ "Effect": "Allow",
118
+ "Action": [
119
+ "ssm:PutParameter",
120
+ "ssm:DeleteParameters",
121
+ "ssm:DescribeParameters",
122
+ "ssm:GetParameters*"
123
+ ],
124
+ "Resource": "*"
125
+ }
126
+ ]
127
+ }
128
+ ```
129
+
130
+
131
+ ## Usage
132
+
133
+ `AwsSsmEnv#load`に渡すオプションの説明です。
134
+
135
+ ### decryption: [Boolean]
136
+
137
+ SecureStringのパラメータを復号化するかどうかを表すフラグ。
138
+ `true`を指定した場合は取得したSecureStringパラメータの値は復号化されている。
139
+ `false`の場合は暗号化されたまた環境変数値として設定される。
140
+ なお、このためのgemなのでデフォルトは`true`(復号化する)。
141
+
142
+ ### overwrite: [Boolean]
143
+
144
+ すでに設定されている環境変数を上書きするかどうかを指定する。
145
+ `true`を指定した場合、環境変数が設定されていても取得したパラメータ値で上書きする。
146
+ `false`を指定した場合はすでに設定されている環境変数を上書きしない。
147
+ デフォルトは`false`(上書きしない)。
148
+ なお、`AwsSsmEnv#load!`を実行した場合、このフラグは自動的に`true`になる。
149
+
150
+ ### client: [Aws::SSM::Client]
151
+
152
+ `Aws::SSM::Client`のインスタンスを指定する。
153
+ すでに生成済みのインスタンスがある場合にそれを設定するためのオプション。
154
+ 生成済みのインスタンスがない場合は`ssm_client_args`を利用する。
155
+
156
+ ### ssm_client_args: [Hash]
157
+
158
+ `Aws::SSM::Client`のコンストラクタに渡すハッシュを指定する。
159
+ 指定しなかった場合は引数なしで`Aws::SSM::Client.new`が呼ばれる。
160
+ 環境変数やEC2インスタンスプロファイルによる認証情報を利用する場合は不要。
161
+
162
+ ### fetch: [Symbol, AwsSsmEnv::Fetcher, Object]
163
+
164
+ パラメータ取得方法を指定する。
165
+ 指定可能な値は`:path`, `:begins_with`または`AwsSsmEnv::Fetcher`を実装したクラスのインスタンス、`each`メソッドを
166
+ 持ったクラスのインスタンスのいずれか。
167
+ 何も指定されていない場合は`:path`として扱われるが、後述の`begins_with`が指定されていた場合は自動的に`:begins_with`となる。
168
+
169
+ #### `:fetch => :path` or default
170
+
171
+ `:path`を指定した場合はパラメータ階層をパス指定で取得する`AwsSsmEnv::PathFetcher`が利用される。
172
+ この場合は後述の`path`引数が必須となる。また、後述の`recursive`引数を利用する。
173
+ この方法でパラメータを取得する場合は指定するパスに対して`ssm:GetParametersByPath`の権限が必要。
174
+ 以下、IAMポリシーの例を示す。
175
+
176
+ ```json
177
+ {
178
+ "Version": "2012-10-17",
179
+ "Statement": [
180
+ {
181
+ "Sid": "",
182
+ "Effect": "Allow",
183
+ "Action": "ssm:GetParametersByPath",
184
+ "Resource": "arn:aws:ssm:YOUR_REGION:YOUR_ACCOUNT_ID:parameter/YOUR_PATH"
185
+ }
186
+ ]
187
+ }
188
+ ```
189
+
190
+ #### `:fetch => :begins_with`
191
+
192
+ `:begins_with`を指定した場合はパラメータ名が指定した文字列から開始するパラメータを取得する`AwsSsmEnv::BeginsWithFetcher`が利用される。
193
+ この場合は後述の`begins_with`引数が必須となる。
194
+ この方法でパラメータを取得する場合は指定するパスに対して`ssm:DescribeParameters`および`ssm:GetParameters`の権限が必要。
195
+ 以下、IAMポリシーの例を示す。
196
+
197
+ ```json
198
+ {
199
+ "Version": "2012-10-17",
200
+ "Statement": [
201
+ {
202
+ "Sid": "",
203
+ "Effect": "Allow",
204
+ "Action": "ssm:DescribeParameters",
205
+ "Resource": "arn:aws:ssm:YOUR_REGION:YOUR_ACCOUNT_ID:parameter"
206
+ },
207
+ {
208
+ "Sid": "",
209
+ "Effect": "Allow",
210
+ "Action": "ssm:GetParameters",
211
+ "Resource": "arn:aws:ssm:YOUR_REGION:YOUR_ACCOUNT_ID:parameter/YOUR_PREFIX*"
212
+ }
213
+ ]
214
+ }
215
+ ```
216
+
217
+ #### other
218
+
219
+ `fetch`に`AwsSsmEnv::Fetcher`を実装したクラスのインスタンス、もしくは`each`メソッドを持つインスタンスを指定した場合はそのインスタンスをそのまま利用する。
220
+
221
+ ### naming: [Symbol, AwsSsmEnv::NamingStrategy, Object]
222
+
223
+ 環境変数名を導出方法を指定する。
224
+ 指定可能な値は`:basename`, `:snakecase`または`AwsSsmEnv::NamingStrategy`を実装したクラスのインスタンス、`parse_name`メソッドを持ったクラスのインスタンスのいずれか。
225
+ デフォルトは`:basename`。
226
+
227
+ #### `:naming => :basename` or default
228
+
229
+ `naming`を指定しなかった場合、もしくは`:basename`を指定した場合はパラメータ階層の最後の階層を変数名とする`AwsSsmEnv::BasenameNamingStrategy`が利用される。
230
+ この場合、例えば`/myapp/production/DB_PASSWORD`というパラメータ名であれば`ENV['DB_PASSWORD']`にパラメータ値がインジェクションされる。
231
+
232
+ #### `:naming => :snakecase`
233
+
234
+ `:snakecase`を指定した場合はパラメータ名のスラッシュ区切りをアンダースコア区切りにした結果を大文字に変換して環境変数名とする`AwsSsmEnv::SnakeCaseNamingStrategy`が利用される。
235
+ この場合、例えば`/myapp/production/DB_PASSWORD`というパラメータ名であれば`ENV['MYAPP_PRODUCTION_DB_PASSWORD']`にパラメータ値がインジェクションされる。
236
+ 後述の`removed_prefix`引数で除外する先頭文字列を指定することができる。
237
+ また、後述の`delimiter`オプションでアンダースコアに変換する文字を指定できる。
238
+ 以下の例では`/myapp/production/db.password`というパラメータが`ENV['DB_PASSWORD']`にインジェクションされる。
239
+
240
+ ```ruby
241
+ AwsSsmEnv.load!(
242
+ naming: :snakecase,
243
+ removed_prefix: '/myapp/production',
244
+ delimiter: /[\/.]/
245
+ )
246
+ ```
247
+
248
+ #### other
249
+
250
+ `AwsSsmEnv::NamingStrategy`を実装したクラスのインスタンス、もしくは`parse_name`メソッドを持つ
251
+ インスタンスを指定した場合はそのインスタンスをそのまま利用する。
252
+
253
+ ### path: [String]
254
+
255
+ `fetch`に何も指定していない場合、もしくは`:path`を指定した場合は必須となる。
256
+ パラメータを取得するパス階層を指定する。
257
+ 下の例では`/myapp/web/production`直下のパラメータが取得される。
258
+
259
+ ```ruby
260
+ AwsSsmEnv.load(path: '/myapp/web/production')
261
+ ```
262
+
263
+ #### recursive: [Boolean]
264
+
265
+ `fetch`に何も指定していない場合、もしくは`:path`を指定した場合に利用する。
266
+ 指定したパス階層以下のパラメータをすべて取得する。
267
+ 下の例では`/myapp/web/production`以下すべてのパラメータが取得される。
268
+
269
+ ```ruby
270
+ AwsSsmEnv.load(path: '/myapp/web/production', recursive: true)
271
+ ```
272
+
273
+ ### begins_with: [String, Array<String>]
274
+
275
+ `fetch`に`:begins_with`を指定した場合は必須となる。
276
+ 取得するパラメータ名のプレフィクスを指定する。配列で複数指定することも可能(OR条件となる)。
277
+ 下の例では`myapp.web.production`で始まる名前のパラメータが取得される。
278
+
279
+ ```ruby
280
+ AwsSsmEnv.load(path: 'myapp.web.production')
281
+ ```
282
+
283
+ ### removed_prefix: [String]
284
+
285
+ `naming`に`:snakecase`を指定した場合に利用される。
286
+ 環境変数名から除外するパラメータ名のプレフィクスを指定する。
287
+ `:removed_prefix`が指定されておらず、`:begins_with`もしくは`:path`が指定されていた場合はそれを利用する。
288
+
289
+ ### delimiter: [String, Regexp]
290
+
291
+ `naming`に`:snakecase`を指定した場合に利用される。
292
+ アンダースコアに変換する文字列もしくは正規表現を指定する。
293
+ デフォルトはスラッシュ(`/`)。
294
+
295
+ ### fetch_size: [Integer]
296
+
297
+ 一度のAWS API実行で取得するパラメータ数を指定する。 `:path`指定の場合は最大値は`10`でデフォルトも`10`。
298
+ `:begins_with`指定の場合は最大値は`50`でデフォルトも`50`である。通常このパラメータを指定することはない。
299
+
300
+
301
+ ## Motivation
302
+
303
+ RailsアプリケーションをECSで起動する場合、環境変数を渡すのが面倒だったので作りました。
304
+
305
+ ## Security
306
+
307
+ シークレット情報を取得するための権限を付与しなければならないため、セキュリティ運用には十分な注意が必要です。
308
+
309
+ EC2インスタンスプロファイルが設定されていた場合、そのEC2上であればどのアカウントでもパラメータが見えるようになるため、
310
+ EC2インスタンスプロファイルとは別にIAMユーザを用意するなどセキュリティレベルを上げる工夫が必要です。
311
+
312
+ EC2にログインできるのが管理者のみであればファイルで持つのと大差ありません。
313
+
314
+ `AWS Fargate`であればコンテナ上でコマンドの実行は困難なため、このリスクは軽減されます。
315
+
316
+ ## License
317
+
318
+ Apache License 2.0
319
+
320
+ ## Contributors
321
+
322
+ - Ryohei Sonoda <[sonodar](https://github.com/sonodar)>
@@ -0,0 +1,160 @@
1
+ require 'aws-ssm-env/loader'
2
+ #
3
+ # AWS EC2 Parameters Storeからパラメータを取得してENVに書き込むモジュール。
4
+ #
5
+ # @author Ryohei Sonoda
6
+ # @since 0.1.0
7
+ module AwsSsmEnv
8
+ module_function
9
+
10
+ # メイン処理。EC2 Parameter Storeからパラメータを取得して環境変数にインジェクションする。
11
+ #
12
+ # @param [Hash] args この処理で利用するすべての引数をまとめて渡す。
13
+ #
14
+ # @option args [Boolean] decryption
15
+ #
16
+ # SecureStringのパラメータを復号化するかどうかを表すフラグ。
17
+ # `true`を指定した場合は取得したSecureStringパラメータの値は復号化されている。
18
+ # `false`の場合は暗号化されたまた環境変数値として設定される。
19
+ # なお、このためのgemなのでデフォルトは`true`(復号化する)。
20
+ #
21
+ # @option args [Boolean] overwrite
22
+ #
23
+ # すでに設定されている環境変数を上書きするかどうかを指定する。
24
+ # `true`を指定した場合、環境変数が設定されていても取得したパラメータ値で上書きする。
25
+ # `false`を指定した場合はすでに設定されている環境変数を上書きしない。
26
+ # デフォルトは`false`(上書きしない)。
27
+ # なお、`AwsSsmEnv#load!`を実行した場合、このフラグは自動的に`true`になる。
28
+ #
29
+ # @option args [Aws::SSM::Client] :client
30
+ #
31
+ # `Aws::SSM::Client`のインスタンスを指定する。
32
+ # すでに生成済みのインスタンスがある場合にそれを設定するためのオプション。
33
+ # 生成済みのインスタンスがない場合は`ssm_client_args`を利用する。
34
+ #
35
+ # @option args [Hash] :ssm_client_args
36
+ #
37
+ # `Aws::SSM::Client`のコンストラクタに渡すハッシュを指定する。
38
+ # 指定しなかった場合は引数なしで`Aws::SSM::Client.new`が呼ばれる。
39
+ # 環境変数やEC2インスタンスプロファイルによる認証情報を利用する場合は不要。
40
+ #
41
+ # @option args [Symbol, AwsSsmEnv::Fetcher, Object] :fetch
42
+ #
43
+ # パラメータ取得方法を指定する。
44
+ # 指定可能な値は`:path`, `:begins_with`または`AwsSsmEnv::Fetcher`を実装したクラスのインスタンス、`each`メソッドを
45
+ # 持ったクラスのインスタンスのいずれか。
46
+ # 何も指定されていない場合は`:path`として扱われるが、後述の`begins_with`が指定されていた場合は自動的に`:begins_with`となる。
47
+ #
48
+ # `:path`を指定した場合はパラメータ階層をパス指定で取得する`AwsSsmEnv::PathFetcher`が利用される。
49
+ # この場合は後述の`path`引数が必須となる。また、後述の`recursive`引数を利用する。
50
+ # この方法でパラメータを取得する場合は指定するパスに対して`ssm:GetParametersByPath`の権限が必要。
51
+ # 以下、IAMポリシーの例を示す。
52
+ # {
53
+ # "Version": "2012-10-17",
54
+ # "Statement": [
55
+ # {
56
+ # "Sid": "",
57
+ # "Effect": "Allow",
58
+ # "Action": "ssm:GetParametersByPath",
59
+ # "Resource": "arn:aws:ssm:YOUR_REGION:YOUR_ACCOUNT_ID:parameter/your_path"
60
+ # }
61
+ # ]
62
+ # }
63
+ #
64
+ # `:begins_with`を指定した場合はパラメータ名が指定した文字列から開始するパラメータを取得する`AwsSsmEnv::BeginsWithFetcher`が利用される。
65
+ # この場合は後述の`begins_with`引数が必須となる。
66
+ # この方法でパラメータを取得する場合は指定するパスに対して`ssm:DescribeParameters`および`ssm:GetParameters`の権限が必要。
67
+ # 以下、IAMポリシーの例を示す。
68
+ # {
69
+ # "Version": "2012-10-17",
70
+ # "Statement": [
71
+ # {
72
+ # "Sid": "",
73
+ # "Effect": "Allow",
74
+ # "Action": "ssm:DescribeParameters",
75
+ # "Resource": "arn:aws:ssm:YOUR_REGION:YOUR_ACCOUNT_ID:parameter"
76
+ # },
77
+ # {
78
+ # "Sid": "",
79
+ # "Effect": "Allow",
80
+ # "Action": "ssm:GetParameters",
81
+ # "Resource": "arn:aws:ssm:YOUR_REGION:YOUR_ACCOUNT_ID:parameter/your_path/*"
82
+ # }
83
+ # ]
84
+ # }
85
+ #
86
+ # `fetch`に`AwsSsmEnv::Fetcher`を実装したクラスのインスタンス、もしくは`each`メソッドを持つ
87
+ # インスタンスを指定した場合はそのインスタンスをそのまま利用する。
88
+ #
89
+ # @option args [Symbol, AwsSsmEnv::NamingStrategy, Object] :naming
90
+ #
91
+ # 環境変数名を導出方法を指定する。
92
+ # 指定可能な値は`:basename`, `:snakecase`または`AwsSsmEnv::NamingStrategy`を実装したクラスのインスタンス、`parse_name`メソッドを持ったクラスのインスタンスのいずれか。
93
+ # デフォルトは`:basename`。
94
+ #
95
+ # `naming`を指定しなかった場合、もしくは`:basename`を指定した場合はパラメータ階層の最後の階層を変数名とする`AwsSsmEnv::BasenameNamingStrategy`が利用される。
96
+ # この場合、例えば`/myapp/production/DB_PASSWORD`というパラメータ名であれば`ENV['DB_PASSWORD']`にパラメータ値がインジェクションされる。
97
+ #
98
+ # `:snakecase`を指定した場合はパラメータ名のスラッシュ区切りをアンダースコア区切りにした結果を大文字に変換して環境変数名とする`AwsSsmEnv::SnakeCaseNamingStrategy`が利用される。
99
+ # この場合、例えば`/myapp/production/DB_PASSWORD`というパラメータ名であれば`ENV['MYAPP_PRODUCTION_DB_PASSWORD']`にパラメータ値がインジェクションされる。
100
+ # 後述の`removed_prefix`引数で除外する先頭文字列を指定することができる。
101
+ # また、後述の`delimiter`オプションでアンダースコアに変換する文字を指定できる。
102
+ # 以下の例では`/myapp/production/db/password`というパラメータが`ENV['DB_PASSWORD']`にインジェクションされる。
103
+ # > AwsSsmEnv.load(naming: :snakecase, removed_prefix: '/myapp/production')
104
+ #
105
+ # `AwsSsmEnv::NamingStrategy`を実装したクラスのインスタンス、もしくは`parse_name`メソッドを持つ
106
+ # インスタンスを指定した場合はそのインスタンスをそのまま利用する。
107
+ #
108
+ # @option args [String] :path
109
+ #
110
+ # `fetch`に何も指定していない場合、もしくは`:path`を指定した場合は必須となる。
111
+ # パラメータを取得するパス階層を指定する。
112
+ # 下の例では`/myapp/web/production`直下のパラメータが取得される。
113
+ # > AwsSsmEnv.load(path: '/myapp/web/production')
114
+ #
115
+ # @option args [Boolean] :recursive
116
+ #
117
+ # `fetch`に何も指定していない場合、もしくは`:path`を指定した場合に利用する。
118
+ # 指定したパス階層以下のパラメータをすべて取得する。
119
+ # 下の例では`/myapp/web/production`以下すべてのパラメータが取得される。
120
+ # > AwsSsmEnv.load(path: '/myapp/web/production', recursive: true)
121
+ #
122
+ # @option args [String, Array<String>] :begins_with
123
+ #
124
+ # `fetch`に`:begins_with`を指定した場合は必須となる。
125
+ # 取得するパラメータ名のプレフィクスを指定する。配列で複数指定することも可能(OR条件となる)。
126
+ # 下の例では`myapp.web.production`で始まる名前のパラメータが取得される。
127
+ #
128
+ # 下の例では 'myapp.web.production' で始まる名前のパラメータが取得される。
129
+ # irb> AwsSsmEnv.load(path: 'myapp.web.production')
130
+ #
131
+ # @option args [String] :removed_prefix
132
+ #
133
+ # `naming`に`:snakecase`を指定した場合に利用される。
134
+ # 環境変数名から除外するパラメータ名のプレフィクスを指定する。
135
+ # `:removed_prefix`が指定されておらず、`:begins_with`もしくは`:path`が指定されていた場合はそれを利用する。
136
+ #
137
+ # @option args [String, Regexp] :delimiter
138
+ #
139
+ # `naming`に`:snakecase`を指定した場合に利用される。
140
+ # アンダースコアに変換する文字列もしくは正規表現を指定する。
141
+ # デフォルトはスラッシュ(`/`)。
142
+ #
143
+ # @option args [Integer] fetch_size
144
+ #
145
+ # 一度のAWS API実行で取得するパラメータ数を指定する。 `:path`指定の場合は最大値は`10`でデフォルトも`10`。
146
+ # `:begins_with`指定の場合は最大値は`50`でデフォルトも`50`である。通常このパラメータを指定することはない。
147
+ #
148
+ # AwsSsmEnv::Loader#load の委譲メソッド。
149
+ #
150
+ # @see AwsSsmEnv::Loader#load
151
+ def load(**args)
152
+ AwsSsmEnv::Loader.load(args)
153
+ end
154
+
155
+ # `overwrite`オプションを付与した AwsSsmEnv::Loader#load の委譲メソッド。
156
+ # @see AwsSsmEnv::Loader#load
157
+ def load!(**args)
158
+ AwsSsmEnv::Loader.load(args.merge(overwrite: true))
159
+ end
160
+ end