From 0eec9576597924ee34e5625c89e400d85d5e02f4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=9C=92=E7=94=B0=20=E4=BA=AE=E5=B9=B3?= Date: Mon, 29 Dec 2025 17:35:36 +0900 Subject: [PATCH 1/2] =?UTF-8?q?refactor:=20=E3=83=9E=E3=83=AB=E3=83=81?= =?UTF-8?q?=E8=A8=80=E8=AA=9E=E5=AF=BE=E5=BF=9C=E3=81=AE=E3=81=9F=E3=82=81?= =?UTF-8?q?=E3=83=A2=E3=83=8E=E3=83=AC=E3=83=9D=E6=A7=8B=E9=80=A0=E3=81=AB?= =?UTF-8?q?=E7=A7=BB=E8=A1=8C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Ruby gemファイルをruby/サブディレクトリに移動 - gemspecをgit ls-filesからDir.globに変更 - GitHub Actionsワークフローをruby-プレフィックス付きにリネーム - ワークフローにworking-directoryとpathsフィルターを追加 - ルートREADME.md(英語)とREADME_ja.md(日本語)を作成 - ユースケース(Lambda, SageMaker)と開発経緯を追加 - Python, Go, Node.js, Rust, Java, .NET実装用の構造を準備 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 --- .github/workflows/{lint.yml => ruby-lint.yml} | 18 +- .../{publish.yml => ruby-publish.yml} | 7 +- .github/workflows/{test.yml => ruby-test.yml} | 15 +- README.md | 367 ++---------------- README_ja.md | 335 ++-------------- .rubocop.yml => ruby/.rubocop.yml | 0 CHANGELOG.md => ruby/CHANGELOG.md | 0 Gemfile => ruby/Gemfile | 0 ruby/LICENSE | 201 ++++++++++ ruby/README.md | 355 +++++++++++++++++ ruby/README_ja.md | 322 +++++++++++++++ Rakefile => ruby/Rakefile | 0 .../aws-ssm-env.gemspec | 11 +- {lib => ruby/lib}/aws-ssm-env.rb | 0 {lib => ruby/lib}/aws-ssm-env/fetcher.rb | 0 .../lib}/aws-ssm-env/fetchers/begins_with.rb | 0 .../lib}/aws-ssm-env/fetchers/factory.rb | 0 .../lib}/aws-ssm-env/fetchers/path.rb | 0 {lib => ruby/lib}/aws-ssm-env/loader.rb | 0 .../aws-ssm-env/naming_strategies/basename.rb | 0 .../aws-ssm-env/naming_strategies/factory.rb | 0 .../naming_strategies/snakecase.rb | 0 .../lib}/aws-ssm-env/naming_strategy.rb | 0 {lib => ruby/lib}/aws-ssm-env/version.rb | 0 .../basename_naming_strategy_spec.rb | 0 .../aws_ssm_env/begins_with_fetcher_spec.rb | 0 .../spec}/aws_ssm_env/fetcher_factory_spec.rb | 0 .../spec}/aws_ssm_env/fetcher_spec.rb | 0 .../spec}/aws_ssm_env/loader_spec.rb | 0 .../naming_strategy_factory_spec.rb | 0 .../spec}/aws_ssm_env/naming_strategy_spec.rb | 0 {spec => ruby/spec}/aws_ssm_env/parameter.rb | 0 .../spec}/aws_ssm_env/path_fetcher_spec.rb | 0 .../snake_case_naming_strategy_spec.rb | 0 {spec => ruby/spec}/aws_ssm_env_spec.rb | 0 {spec => ruby/spec}/spec_helper.rb | 0 36 files changed, 972 insertions(+), 659 deletions(-) rename .github/workflows/{lint.yml => ruby-lint.yml} (64%) rename .github/workflows/{publish.yml => ruby-publish.yml} (91%) rename .github/workflows/{test.yml => ruby-test.yml} (69%) rename .rubocop.yml => ruby/.rubocop.yml (100%) rename CHANGELOG.md => ruby/CHANGELOG.md (100%) rename Gemfile => ruby/Gemfile (100%) create mode 100644 ruby/LICENSE create mode 100644 ruby/README.md create mode 100644 ruby/README_ja.md rename Rakefile => ruby/Rakefile (100%) rename aws-ssm-env.gemspec => ruby/aws-ssm-env.gemspec (78%) rename {lib => ruby/lib}/aws-ssm-env.rb (100%) rename {lib => ruby/lib}/aws-ssm-env/fetcher.rb (100%) rename {lib => ruby/lib}/aws-ssm-env/fetchers/begins_with.rb (100%) rename {lib => ruby/lib}/aws-ssm-env/fetchers/factory.rb (100%) rename {lib => ruby/lib}/aws-ssm-env/fetchers/path.rb (100%) rename {lib => ruby/lib}/aws-ssm-env/loader.rb (100%) rename {lib => ruby/lib}/aws-ssm-env/naming_strategies/basename.rb (100%) rename {lib => ruby/lib}/aws-ssm-env/naming_strategies/factory.rb (100%) rename {lib => ruby/lib}/aws-ssm-env/naming_strategies/snakecase.rb (100%) rename {lib => ruby/lib}/aws-ssm-env/naming_strategy.rb (100%) rename {lib => ruby/lib}/aws-ssm-env/version.rb (100%) rename {spec => ruby/spec}/aws_ssm_env/basename_naming_strategy_spec.rb (100%) rename {spec => ruby/spec}/aws_ssm_env/begins_with_fetcher_spec.rb (100%) rename {spec => ruby/spec}/aws_ssm_env/fetcher_factory_spec.rb (100%) rename {spec => ruby/spec}/aws_ssm_env/fetcher_spec.rb (100%) rename {spec => ruby/spec}/aws_ssm_env/loader_spec.rb (100%) rename {spec => ruby/spec}/aws_ssm_env/naming_strategy_factory_spec.rb (100%) rename {spec => ruby/spec}/aws_ssm_env/naming_strategy_spec.rb (100%) rename {spec => ruby/spec}/aws_ssm_env/parameter.rb (100%) rename {spec => ruby/spec}/aws_ssm_env/path_fetcher_spec.rb (100%) rename {spec => ruby/spec}/aws_ssm_env/snake_case_naming_strategy_spec.rb (100%) rename {spec => ruby/spec}/aws_ssm_env_spec.rb (100%) rename {spec => ruby/spec}/spec_helper.rb (100%) diff --git a/.github/workflows/lint.yml b/.github/workflows/ruby-lint.yml similarity index 64% rename from .github/workflows/lint.yml rename to .github/workflows/ruby-lint.yml index 61b98df..22f9ca6 100644 --- a/.github/workflows/lint.yml +++ b/.github/workflows/ruby-lint.yml @@ -1,14 +1,19 @@ -name: Lint +name: Ruby Lint on: push: branches: [master] + paths: + - 'ruby/**' + - '.github/workflows/ruby-lint.yml' pull_request: paths: - - '.rubocop.yml' - - 'Gemfile.lock' - - '**/*.rb' - - '.github/workflows/lint.yml' + - 'ruby/**' + - '.github/workflows/ruby-lint.yml' + +defaults: + run: + working-directory: ruby jobs: lint: @@ -27,5 +32,6 @@ jobs: with: ruby-version: ${{ matrix.ruby-version }} bundler-cache: true - - name: Run rspec + working-directory: ruby + - name: Run rubocop run: bundle exec rubocop diff --git a/.github/workflows/publish.yml b/.github/workflows/ruby-publish.yml similarity index 91% rename from .github/workflows/publish.yml rename to .github/workflows/ruby-publish.yml index a77a34e..3d03b57 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/ruby-publish.yml @@ -1,5 +1,5 @@ # refs: https://ybiquitous.me/blog/2022/release-gem-using-github-actions -name: Publish +name: Ruby Publish on: workflow_dispatch: @@ -8,6 +8,10 @@ on: description: "One-time password for RubyGems.org" required: true +defaults: + run: + working-directory: ruby + concurrency: group: ${{ github.workflow }} cancel-in-progress: true @@ -26,6 +30,7 @@ jobs: with: ruby-version: '3.1' bundler-cache: true + working-directory: ruby # https://docs.github.com/en/actions/automating-builds-and-tests/building-and-testing-ruby#publishing-gems - name: Publish to RubyGems diff --git a/.github/workflows/test.yml b/.github/workflows/ruby-test.yml similarity index 69% rename from .github/workflows/test.yml rename to .github/workflows/ruby-test.yml index 264b7b9..2f51c5b 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/ruby-test.yml @@ -1,13 +1,19 @@ -name: Test +name: Ruby Test on: push: branches: [master] + paths: + - 'ruby/**' + - '.github/workflows/ruby-test.yml' pull_request: paths: - - 'Gemfile.lock' - - '**/*.rb' - - '.github/workflows/test.yml' + - 'ruby/**' + - '.github/workflows/ruby-test.yml' + +defaults: + run: + working-directory: ruby env: AWS_REGION: ap-northeast-1 @@ -29,5 +35,6 @@ jobs: with: ruby-version: ${{ matrix.ruby-version }} bundler-cache: true + working-directory: ruby - name: Run rspec run: bundle exec rspec diff --git a/README.md b/README.md index 97e2ed5..02841d8 100644 --- a/README.md +++ b/README.md @@ -1,355 +1,46 @@ -[![Build Status](https://travis-ci.org/sonodar/aws-ssm-env-ruby.svg?branch=master)](https://travis-ci.org/sonodar/aws-ssm-env-ruby) -[![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) -[![Gem Version](https://badge.fury.io/rb/aws-ssm-env.svg)](https://badge.fury.io/rb/aws-ssm-env) - # aws-ssm-env -This tool sets parameters acquired from `AWS EC2 Parameter Store` as environment variables. - -By default, the last hierarchy of the parameter name is -set as the environment variable name. - -For example, if the parameter name is `/staging/secure/DB_PASSWORD`, -the parameter value is set to `ENV['DB_PASSWORD']`. -The naming of environment variables is optional and can be customized. -(described later) - -## Installation - -This gem has been tested with ruby version 2.7 to 3.3. - -``` -gem install aws-ssm-env -``` - -### Rails - -```ruby -# Gemfile -gem 'aws-ssm-env', group: :aws -``` - -```ruby -# config/application.rb -if defined?(AwsSsmEnv) - AwsSsmEnv.load(path: "/myapp/#{ENV['RAILS_ENV']}", recursive: true) -end -``` - -### Other ruby program - -```ruby -require 'aws-ssm-env' -AwsSsmEnv.load!(begins_with: "myapp.#{ENV['RACK_ENV']}.") -``` - -## Quick Start - -First of all, register the parameters in `AWS EC2 Parameter Store`. - -```shell -# ex) register /myservice/staging/RDS_PASSWORD with SecureString -aws ssm --region ap-northeast-1 put-parameter \ - --name /myservice/staging/RDS_PASSWORD \ - --type SecureString --value -``` - -Then, set authentication information of AWS. -For example, you can use environment variables as follows, - -```shell -export AWS_ACCESS_KEY_ID=YOURACCESSKEYID -export AWS_SECRET_ACCESS_KEY=YOURSECRETKEY -bundle exec rails start -``` - -Or, you can pass `ssm_client_args` as the argument for `AwsSsmEnv#load`: - -```ruby -AwsSsmEnv.load( - path: "/myservice/#{ENV['RAILS_ENV']}", - ssm_client_args: { - access_key_id: 'ACCESS_KEY_ID', - secret_access_key: 'SECRET_ACCESS_KEY', - region: 'ap-northeast-1', - } -) -``` - -You can also use `Aws.config`. - -```ruby - -if defined?(AwsSsmEnv) - AWS.config({ - access_key_id: 'ACCESS_KEY_ID', - secret_access_key: 'SECRET_ACCESS_KEY', - region: 'ap-northeast-1', - }) - AwsSsmEnv.load(path: "/myservice/#{ENV['RAILS_ENV']}") -end -``` - -For details, refer to the document of aws-sdk. - -## Develop - -### Unit test - -```shell -bundle exec rspec -bundle exec rubocop -``` - -### Integration test - -```shell -export AWS_ACCESS_KEY_ID=xxxx -export AWS_SECRET_ACCESS_KEY=xxxx -export AWS_REGION=xxxx -bundle exec rspec --tag integration -``` - -IAM users who run tests need the following authorization policy: - -```json -{ - "Version": "2012-10-17", - "Statement": [ - { - "Sid": "", - "Effect": "Allow", - "Action": [ - "ssm:PutParameter", - "ssm:DeleteParameters", - "ssm:DescribeParameters", - "ssm:GetParameters*" - ], - "Resource": "*" - } - ] -} -``` - - -## Usage - -Here are descriptions of the options passed to `AwsSsmEnv#load`. - -### decryption: [Boolean] - -Flag indicating whether to decrypt SecureString parameters. -If `true` is specified, the value of the acquired SecureString parameter is decrypted. -In case of `false` it is set as encrypted and environment variable value. -Since it is a gem for this, the default is `true` (decrypt). - -### overwrite: [Boolean] - -Specify whether to overwrite an already set environment variable. -If `true` is specified, even if the environment variable is set, -it overwrites it with the acquired parameter value. -If `false` is specified, do not overwrite already set environment variables. -The default is `false` (do not overwrite). -If you invoke `AwsSsmEnv#load!`, This flag will automatically be set to `true`. +A library that retrieves parameters from AWS EC2 Parameter Store (Systems Manager Parameter Store) and sets them as environment variables. -### client: [Aws::SSM::Client] +## Use Cases -Specify an instance of `Aws::SSM::Client`. -An option to set it if there are already created instances. -If there are no instances created, use `ssm_client_args` instead. +This library is useful in environments where native integration with Parameter Store is not provided: -### ssm_client_args: [Hash] +- **AWS Lambda Function** - When configuration exceeds the 4KB environment variable limit +- **Amazon SageMaker Processing Job** - When handling secrets within processing jobs +- **EC2 Instances** - When dynamically loading configuration at application startup +- **On-premises environments** - When accessing Parameter Store from environments with AWS credentials -Specify a hash to pass to the constructor of `Aws::SSM::Client`. -If not specified, `Aws::SSM::Client#new` is called with an empty argument. -It is unnecessary when using environment variable -or authentication information by `EC2 InstanceProfile`. +## Background -### fetch: [Symbol, AwsSsmEnv::Fetcher, Object] +This library was developed before Amazon ECS implemented native integration with Parameter Store via the `secrets` directive. At that time, a mechanism was needed to securely handle secrets in ECS tasks by retrieving parameters from Parameter Store and setting them as environment variables at application startup. -Specify parameter fetch strategy. -Possible values are `:path`,`:begins_with` -or an instance of a class that implements `AwsSsmEnv::Fetcher`, -or an instance of a class with a `each` method. -If nothing is specified, it is treated as `:path`. -But when `begins_with` (which is described later) is specified, -it will automatically be `:begins_with`. +Currently, ECS/Fargate has native integration with Parameter Store and Secrets Manager, so there is no need to use this library for container workloads. -#### `:fetch => :path` or default +## Supported Languages -When `:path` is specified, `AwsSsmEnv::PathFetcher` which fetches -parameter hierarchy by path specification is used. -In this case, the `path` argument described below is required. -Also, the `recursive` argument (described later) is used. -When acquiring parameters in this way, you need `ssm:GetParametersByPath` authority -for the specified path. -An example of the IAM policy is shown below. +| Language | Directory | Status | +|----------|-----------|--------| +| Ruby | [ruby/](./ruby/) | Available | +| Python | python/ | Coming Soon | +| Go | go/ | Coming Soon | +| Node.js | nodejs/ | Coming Soon | +| Rust | rust/ | Coming Soon | +| Java | java/ | Coming Soon | +| .NET | dotnet/ | Coming Soon | -```json -{ - "Version": "2012-10-17", - "Statement": [ - { - "Sid": "", - "Effect": "Allow", - "Action": "ssm:GetParametersByPath", - "Resource": "arn:aws:ssm:YOUR_REGION:YOUR_ACCOUNT_ID:parameter/YOUR_PATH" - } - ] -} -``` +## Features -#### `:fetch => :begins_with` +- Retrieve parameters by hierarchy (path) or prefix (begins_with) +- Automatic decryption of SecureString parameters +- Flexible environment variable naming strategies -If `:begins_with` is specified, `AwsSsmEnv::BeginsWithFetcher` is used to fetch -parameters starting from the character string specified by the parameter name. -In this case, the `begins_with` argument described below is required. -When acquiring parameters in this way, -you need the authority of `ssm:DescribeParameters` and `ssm:GetParameters` -for the specified path. -An example of the IAM policy is shown below. +## Quick Links -```json -{ - "Version": "2012-10-17", - "Statement": [ - { - "Sid": "", - "Effect": "Allow", - "Action": "ssm:DescribeParameters", - "Resource": "arn:aws:ssm:YOUR_REGION:YOUR_ACCOUNT_ID:parameter" - }, - { - "Sid": "", - "Effect": "Allow", - "Action": "ssm:GetParameters", - "Resource": "arn:aws:ssm:YOUR_REGION:YOUR_ACCOUNT_ID:parameter/YOUR_PREFIX*" - } - ] -} -``` - -#### other - -If you specify an instance of a class that implements `AwsSsmEnv::Fetcher` in` fetch`, -or an instance with a `each` method, that instance will be used as is. - -### naming: [Symbol, AwsSsmEnv::NamingStrategy, Object] - -Specify the naming strategy for the environment variable name. -Possible values are `:basename`,`:snakecase` -or an instance of a class that implements `AwsSsmEnv::NamingStrategy`, -or an instance of a class with a `parse_name` method. -If nothing is specified, it is treated as `:basename`. - -#### `:naming => :basename` or default - -If `naming` is not specified or `:basename` is specified, -`AwsSsmEnv::BasenameNamingStrategy` whose variable name is -the last hierarchy of the parameter hierarchy is used. -In this case, for example, if the parameter name is `/myapp/production/DB_PASSWORD`, -the parameter value is set to `ENV['DB_PASSWORD']`. - -#### `:naming => :snakecase` - -When `:snakecase` is specified, `AwsSsmEnv::SnakeCaseNamingStrategy` which uses -the underscore delimiter of the parameter name's slash delimiter and converts -it to uppercase letters as the environment variable name is used. -In this case, for example, if the parameter name is `/myapp/production/DB_PASSWORD`, -the parameter value is set to `ENV['MYAPP_PRODUCTION_DB_PASSWORD']`. -You can specify first part of string to exclude with -the `removed_prefix` argument described below. -In addition, you can specify characters to be converted to -underscores with the `delimiter` option described below. -In the following example, the parameter `/myapp/production/db.password` is -set to `ENV['DB_PASSWORD']`. - -```ruby -AwsSsmEnv.load!( - naming: :snakecase, - removed_prefix: '/myapp/production', - delimiter: /[\/.]/ -) -``` - -#### other - -If you specify an instance of a class that implements `AwsSsmEnv::NamingStrategy` in` fetch`, -or an instance with a `parse_name` method, that instance is used as is. - - -### path: [String] - -Required if nothing is specified for `fetch` or if `:path` is specified. -This option specifies the path hierarchy for acquiring parameters from `Parameter Store`. -In the example below, the parameter immediately under `/myapp/web/production` is acquired. - -```ruby -AwsSsmEnv.load(path: '/myapp/web/production') -``` - -#### recursive: [Boolean] - -Used when no parameter is specified for `fetch` option or when `:path` is specified. -If true is specified, acquires all parameters below the specified path hierarchy. -If nothing is specified this parameter, it is treated as `false`(one level). -In the following example, all parameters below `/myapp/web/production` are acquired. - -```ruby -AwsSsmEnv.load(path: '/myapp/web/production', recursive: true) -``` - -### begins_with: [String, Array] - -Required if `:begins_with` is specified in `fetch`. -You can specify the prefix of the parameter name to be acquired by this option. -It is also possible to specify more than one in an array (OR condition). -In the example below, parameters with names starting with `myapp.web.production` are acquired. - -```ruby -AwsSsmEnv.load(path: 'myapp.web.production') -``` - -### removed_prefix: [String] - -Used when `:snakecase` is specified in `naming`. -By this option, you can specify the prefix of the parameter name to exclude -from the environment variable name. -If `:removed_ prefix` is not specified, and `:begins_with` or `:path` is specified, that will be used. - -### delimiter: [String, Regexp] - -Used when `:snakecase` is specified in `naming`. -By this option, you can specify a string or a regular expression to be converted to an underscore. -The default is a slash (`/`). - -### fetch_size: [Integer] - -Specify the number of parameters to be acquired with one execution of AWS API. -If `:path` is specified, the maximum value is `10` and the default is `10`. -If `:begins_with` is specified, the maximum value is `50` and the default is `50`. -Usually this parameter is never specified. - -## Security - -Because you must grant authority to acquire secret information, -careful attention is required for security operation. - - -When the `EC2 InstanceProfile` is set, the parameters can be seen by any account on EC2, -It is necessary to improve the security level by preparing an IAM User separately -from the `EC2 InstanceProfile`. - -If it is only the administrator that you can log in to EC2, -it is not much different from having it in a file. - -Since `AWS Fargate` makes it difficult to execute commands on containers, -this risk is mitigated. +- [Ruby gem documentation](./ruby/README.md) +- [Ruby gem (Japanese)](./ruby/README_ja.md) +- [Japanese README](./README_ja.md) ## License -Apache License 2.0 - -## Contributors - -- Ryohei Sonoda <[sonodar](https://github.com/sonodar)> +Apache License 2.0 - see [LICENSE](./LICENSE) diff --git a/README_ja.md b/README_ja.md index ead4ffd..cd0c032 100644 --- a/README_ja.md +++ b/README_ja.md @@ -1,322 +1,47 @@ -[![Build Status](https://travis-ci.org/sonodar/aws-ssm-env-ruby.svg?branch=master)](https://travis-ci.org/sonodar/aws-ssm-env-ruby) -[![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) -[![Gem Version](https://badge.fury.io/rb/aws-ssm-env.svg)](https://badge.fury.io/rb/aws-ssm-env) - # aws-ssm-env -AWS EC2 Parameter Storeから取得したパラメータを環境変数として設定します。 - -デフォルトでは、パラメータ名の最後の階層が環境変数名として設定されます。 - -例えば、`/staging/secure/DB_PASSWORD`というパラメータ名であれば、`ENV['DB_PASSWORD']`にパラメータ値が設定されます。 -この環境変数のネーミングはオプションでカスタマイズ可能です。(後述) - -## Installation - -このgemはRuby2.7から3.3まででテストされています。 - -``` -gem install aws-ssm-env -``` - -### Rails - -```ruby -# Gemfile -gem 'aws-ssm-env', group: :aws -``` - -```ruby -# config/application.rb -if defined?(AwsSsmEnv) - AwsSsmEnv.load(path: "/myapp/#{ENV['RAILS_ENV']}", recursive: true) -end -``` - -### Other ruby program - -```ruby -require 'aws-ssm-env' -AwsSsmEnv.load!(begins_with: "myapp.#{ENV['RACK_ENV']}.") -``` - -## Quick Start - -事前にAWS EC2 Parameter Storeにパラメータを登録しておく必要があります。 - -```shell -# 例) /myservice/staging/RDS_PASSWORDをSecureStringで登録 -aws ssm --region ap-northeast-1 put-parameter \ - --name /myservice/staging/RDS_PASSWORD \ - --type SecureString --value -``` - -AWSの認証情報を設定します。例えば、以下のように環境変数を利用したり、 - -```shell -export AWS_ACCESS_KEY_ID=YOURACCESSKEYID -export AWS_SECRET_ACCESS_KEY=YOURSECRETKEY -bundle exec rails start -``` - -引数で`ssm_client_args`を渡したり、 - -```ruby -AwsSsmEnv.load( - fetch: "/myservice/#{ENV['RAILS_ENV']}", - ssm_client_args: { - access_key_id: 'ACCESS_KEY_ID', - secret_access_key: 'SECRET_ACCESS_KEY', - region: 'ap-northeast-1', - } -) -``` - -`Aws.config`を利用することもできます。 - -```ruby - -if defined?(AwsSsmEnv) - AWS.config({ - access_key_id: 'ACCESS_KEY_ID', - secret_access_key: 'SECRET_ACCESS_KEY', - region: 'ap-northeast-1', - }) - AwsSsmEnv.load(path: "/myservice/#{ENV['RAILS_ENV']}") -end -``` - -詳細はaws-sdkのドキュメントを参照してください。 - -## Develop - -### Unit test - -```shell -bundle exec rspec -bundle exec rubocop -``` - -### Integration test - -```shell -export AWS_ACCESS_KEY_ID=xxxx -export AWS_SECRET_ACCESS_KEY=xxxx -export AWS_REGION=xxxx -bundle exec rspec --tag integration -``` - -IAMユーザには以下の認可ポリシーが必要です。 - -```json -{ - "Version": "2012-10-17", - "Statement": [ - { - "Sid": "", - "Effect": "Allow", - "Action": [ - "ssm:PutParameter", - "ssm:DeleteParameters", - "ssm:DescribeParameters", - "ssm:GetParameters*" - ], - "Resource": "*" - } - ] -} -``` - - -## Usage - -`AwsSsmEnv#load`に渡すオプションの説明です。 - -### decryption: [Boolean] - -SecureStringのパラメータを復号化するかどうかを表すフラグ。 -`true`を指定した場合は取得したSecureStringパラメータの値は復号化されている。 -`false`の場合は暗号化されたまた環境変数値として設定される。 -なお、このためのgemなのでデフォルトは`true`(復号化する)。 - -### overwrite: [Boolean] - -すでに設定されている環境変数を上書きするかどうかを指定する。 -`true`を指定した場合、環境変数が設定されていても取得したパラメータ値で上書きする。 -`false`を指定した場合はすでに設定されている環境変数を上書きしない。 -デフォルトは`false`(上書きしない)。 -なお、`AwsSsmEnv#load!`を実行した場合、このフラグは自動的に`true`になる。 +AWS EC2 Parameter Store (Systems Manager Parameter Store) から +パラメータを取得し、環境変数として設定するライブラリ。 -### client: [Aws::SSM::Client] +## Use Cases -`Aws::SSM::Client`のインスタンスを指定する。 -すでに生成済みのインスタンスがある場合にそれを設定するためのオプション。 -生成済みのインスタンスがない場合は`ssm_client_args`を利用する。 +このライブラリは、Parameter Store とのネイティブ統合が提供されていない以下のような環境で有用です: -### ssm_client_args: [Hash] +- **AWS Lambda Function** - 環境変数の4KB制限を超える設定が必要な場合 +- **Amazon SageMaker Processing Job** - 処理ジョブ内で秘密情報を扱う場合 +- **EC2 インスタンス** - アプリケーション起動時に動的に設定を読み込む場合 +- **オンプレミス環境** - AWS 認証情報を持つ環境から Parameter Store にアクセスする場合 -`Aws::SSM::Client`のコンストラクタに渡すハッシュを指定する。 -指定しなかった場合は引数なしで`Aws::SSM::Client.new`が呼ばれる。 -環境変数やEC2インスタンスプロファイルによる認証情報を利用する場合は不要。 +## Background -### fetch: [Symbol, AwsSsmEnv::Fetcher, Object] +このライブラリは、Amazon ECS が `secrets` ディレクティブで Parameter Store とのネイティブ統合を実装する以前に開発されました。当時は ECS タスクで秘密情報を安全に扱うために、アプリケーション起動時に Parameter Store からパラメータを取得して環境変数に設定する仕組みが必要でした。 -パラメータ取得方法を指定する。 -指定可能な値は`:path`, `:begins_with`または`AwsSsmEnv::Fetcher`を実装したクラスのインスタンス、`each`メソッドを -持ったクラスのインスタンスのいずれか。 -何も指定されていない場合は`:path`として扱われるが、後述の`begins_with`が指定されていた場合は自動的に`:begins_with`となる。 +現在では ECS/Fargate は Parameter Store および Secrets Manager とネイティブ統合されているため、コンテナワークロードでこのライブラリを使用する必要はありません。 -#### `:fetch => :path` or default +## Supported Languages -`:path`を指定した場合はパラメータ階層をパス指定で取得する`AwsSsmEnv::PathFetcher`が利用される。 -この場合は後述の`path`引数が必須となる。また、後述の`recursive`引数を利用する。 -この方法でパラメータを取得する場合は指定するパスに対して`ssm:GetParametersByPath`の権限が必要。 -以下、IAMポリシーの例を示す。 +| Language | Directory | Status | +|----------|-----------|--------| +| Ruby | [ruby/](./ruby/) | Available | +| Python | python/ | Coming Soon | +| Go | go/ | Coming Soon | +| Node.js | nodejs/ | Coming Soon | +| Rust | rust/ | Coming Soon | +| Java | java/ | Coming Soon | +| .NET | dotnet/ | Coming Soon | -```json -{ - "Version": "2012-10-17", - "Statement": [ - { - "Sid": "", - "Effect": "Allow", - "Action": "ssm:GetParametersByPath", - "Resource": "arn:aws:ssm:YOUR_REGION:YOUR_ACCOUNT_ID:parameter/YOUR_PATH" - } - ] -} -``` +## Features -#### `:fetch => :begins_with` +- パラメータ階層(path)またはプレフィックス(begins_with)による取得 +- SecureStringパラメータの自動復号化 +- 柔軟な環境変数命名戦略 -`:begins_with`を指定した場合はパラメータ名が指定した文字列から開始するパラメータを取得する`AwsSsmEnv::BeginsWithFetcher`が利用される。 -この場合は後述の`begins_with`引数が必須となる。 -この方法でパラメータを取得する場合は指定するパスに対して`ssm:DescribeParameters`および`ssm:GetParameters`の権限が必要。 -以下、IAMポリシーの例を示す。 +## Quick Links -```json -{ - "Version": "2012-10-17", - "Statement": [ - { - "Sid": "", - "Effect": "Allow", - "Action": "ssm:DescribeParameters", - "Resource": "arn:aws:ssm:YOUR_REGION:YOUR_ACCOUNT_ID:parameter" - }, - { - "Sid": "", - "Effect": "Allow", - "Action": "ssm:GetParameters", - "Resource": "arn:aws:ssm:YOUR_REGION:YOUR_ACCOUNT_ID:parameter/YOUR_PREFIX*" - } - ] -} -``` - -#### other - -`fetch`に`AwsSsmEnv::Fetcher`を実装したクラスのインスタンス、もしくは`each`メソッドを持つインスタンスを指定した場合はそのインスタンスをそのまま利用する。 - -### naming: [Symbol, AwsSsmEnv::NamingStrategy, Object] - -環境変数名を導出方法を指定する。 -指定可能な値は`:basename`, `:snakecase`または`AwsSsmEnv::NamingStrategy`を実装したクラスのインスタンス、`parse_name`メソッドを持ったクラスのインスタンスのいずれか。 -デフォルトは`:basename`。 - -#### `:naming => :basename` or default - -`naming`を指定しなかった場合、もしくは`:basename`を指定した場合はパラメータ階層の最後の階層を変数名とする`AwsSsmEnv::BasenameNamingStrategy`が利用される。 -この場合、例えば`/myapp/production/DB_PASSWORD`というパラメータ名であれば`ENV['DB_PASSWORD']`にパラメータ値がインジェクションされる。 - -#### `:naming => :snakecase` - -`:snakecase`を指定した場合はパラメータ名のスラッシュ区切りをアンダースコア区切りにした結果を大文字に変換して環境変数名とする`AwsSsmEnv::SnakeCaseNamingStrategy`が利用される。 -この場合、例えば`/myapp/production/DB_PASSWORD`というパラメータ名であれば`ENV['MYAPP_PRODUCTION_DB_PASSWORD']`にパラメータ値がインジェクションされる。 -後述の`removed_prefix`引数で除外する先頭文字列を指定することができる。 -また、後述の`delimiter`オプションでアンダースコアに変換する文字を指定できる。 -以下の例では`/myapp/production/db.password`というパラメータが`ENV['DB_PASSWORD']`にインジェクションされる。 - -```ruby -AwsSsmEnv.load!( - naming: :snakecase, - removed_prefix: '/myapp/production', - delimiter: /[\/.]/ -) -``` - -#### other - -`AwsSsmEnv::NamingStrategy`を実装したクラスのインスタンス、もしくは`parse_name`メソッドを持つ -インスタンスを指定した場合はそのインスタンスをそのまま利用する。 - -### path: [String] - -`fetch`に何も指定していない場合、もしくは`:path`を指定した場合は必須となる。 -パラメータを取得するパス階層を指定する。 -下の例では`/myapp/web/production`直下のパラメータが取得される。 - -```ruby -AwsSsmEnv.load(path: '/myapp/web/production') -``` - -#### recursive: [Boolean] - -`fetch`に何も指定していない場合、もしくは`:path`を指定した場合に利用する。 -指定したパス階層以下のパラメータをすべて取得する。 -下の例では`/myapp/web/production`以下すべてのパラメータが取得される。 - -```ruby -AwsSsmEnv.load(path: '/myapp/web/production', recursive: true) -``` - -### begins_with: [String, Array] - -`fetch`に`:begins_with`を指定した場合は必須となる。 -取得するパラメータ名のプレフィクスを指定する。配列で複数指定することも可能(OR条件となる)。 -下の例では`myapp.web.production`で始まる名前のパラメータが取得される。 - -```ruby -AwsSsmEnv.load(path: 'myapp.web.production') -``` - -### removed_prefix: [String] - -`naming`に`:snakecase`を指定した場合に利用される。 -環境変数名から除外するパラメータ名のプレフィクスを指定する。 -`:removed_prefix`が指定されておらず、`:begins_with`もしくは`:path`が指定されていた場合はそれを利用する。 - -### delimiter: [String, Regexp] - -`naming`に`:snakecase`を指定した場合に利用される。 -アンダースコアに変換する文字列もしくは正規表現を指定する。 -デフォルトはスラッシュ(`/`)。 - -### fetch_size: [Integer] - -一度のAWS API実行で取得するパラメータ数を指定する。 `:path`指定の場合は最大値は`10`でデフォルトも`10`。 -`:begins_with`指定の場合は最大値は`50`でデフォルトも`50`である。通常このパラメータを指定することはない。 - - -## Motivation - -RailsアプリケーションをECSで起動する場合、環境変数を渡すのが面倒だったので作りました。 - -## Security - -シークレット情報を取得するための権限を付与しなければならないため、セキュリティ運用には十分な注意が必要です。 - -EC2インスタンスプロファイルが設定されていた場合、そのEC2上であればどのアカウントでもパラメータが見えるようになるため、 -EC2インスタンスプロファイルとは別にIAMユーザを用意するなどセキュリティレベルを上げる工夫が必要です。 - -EC2にログインできるのが管理者のみであればファイルで持つのと大差ありません。 - -`AWS Fargate`であればコンテナ上でコマンドの実行は困難なため、このリスクは軽減されます。 +- [Ruby gem ドキュメント](./ruby/README.md) +- [Ruby gem ドキュメント (日本語)](./ruby/README_ja.md) +- [English README](./README.md) ## License -Apache License 2.0 - -## Contributors - -- Ryohei Sonoda <[sonodar](https://github.com/sonodar)> +Apache License 2.0 - see [LICENSE](./LICENSE) diff --git a/.rubocop.yml b/ruby/.rubocop.yml similarity index 100% rename from .rubocop.yml rename to ruby/.rubocop.yml diff --git a/CHANGELOG.md b/ruby/CHANGELOG.md similarity index 100% rename from CHANGELOG.md rename to ruby/CHANGELOG.md diff --git a/Gemfile b/ruby/Gemfile similarity index 100% rename from Gemfile rename to ruby/Gemfile diff --git a/ruby/LICENSE b/ruby/LICENSE new file mode 100644 index 0000000..261eeb9 --- /dev/null +++ b/ruby/LICENSE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/ruby/README.md b/ruby/README.md new file mode 100644 index 0000000..97e2ed5 --- /dev/null +++ b/ruby/README.md @@ -0,0 +1,355 @@ +[![Build Status](https://travis-ci.org/sonodar/aws-ssm-env-ruby.svg?branch=master)](https://travis-ci.org/sonodar/aws-ssm-env-ruby) +[![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) +[![Gem Version](https://badge.fury.io/rb/aws-ssm-env.svg)](https://badge.fury.io/rb/aws-ssm-env) + +# aws-ssm-env + +This tool sets parameters acquired from `AWS EC2 Parameter Store` as environment variables. + +By default, the last hierarchy of the parameter name is +set as the environment variable name. + +For example, if the parameter name is `/staging/secure/DB_PASSWORD`, +the parameter value is set to `ENV['DB_PASSWORD']`. +The naming of environment variables is optional and can be customized. +(described later) + +## Installation + +This gem has been tested with ruby version 2.7 to 3.3. + +``` +gem install aws-ssm-env +``` + +### Rails + +```ruby +# Gemfile +gem 'aws-ssm-env', group: :aws +``` + +```ruby +# config/application.rb +if defined?(AwsSsmEnv) + AwsSsmEnv.load(path: "/myapp/#{ENV['RAILS_ENV']}", recursive: true) +end +``` + +### Other ruby program + +```ruby +require 'aws-ssm-env' +AwsSsmEnv.load!(begins_with: "myapp.#{ENV['RACK_ENV']}.") +``` + +## Quick Start + +First of all, register the parameters in `AWS EC2 Parameter Store`. + +```shell +# ex) register /myservice/staging/RDS_PASSWORD with SecureString +aws ssm --region ap-northeast-1 put-parameter \ + --name /myservice/staging/RDS_PASSWORD \ + --type SecureString --value +``` + +Then, set authentication information of AWS. +For example, you can use environment variables as follows, + +```shell +export AWS_ACCESS_KEY_ID=YOURACCESSKEYID +export AWS_SECRET_ACCESS_KEY=YOURSECRETKEY +bundle exec rails start +``` + +Or, you can pass `ssm_client_args` as the argument for `AwsSsmEnv#load`: + +```ruby +AwsSsmEnv.load( + path: "/myservice/#{ENV['RAILS_ENV']}", + ssm_client_args: { + access_key_id: 'ACCESS_KEY_ID', + secret_access_key: 'SECRET_ACCESS_KEY', + region: 'ap-northeast-1', + } +) +``` + +You can also use `Aws.config`. + +```ruby + +if defined?(AwsSsmEnv) + AWS.config({ + access_key_id: 'ACCESS_KEY_ID', + secret_access_key: 'SECRET_ACCESS_KEY', + region: 'ap-northeast-1', + }) + AwsSsmEnv.load(path: "/myservice/#{ENV['RAILS_ENV']}") +end +``` + +For details, refer to the document of aws-sdk. + +## Develop + +### Unit test + +```shell +bundle exec rspec +bundle exec rubocop +``` + +### Integration test + +```shell +export AWS_ACCESS_KEY_ID=xxxx +export AWS_SECRET_ACCESS_KEY=xxxx +export AWS_REGION=xxxx +bundle exec rspec --tag integration +``` + +IAM users who run tests need the following authorization policy: + +```json +{ + "Version": "2012-10-17", + "Statement": [ + { + "Sid": "", + "Effect": "Allow", + "Action": [ + "ssm:PutParameter", + "ssm:DeleteParameters", + "ssm:DescribeParameters", + "ssm:GetParameters*" + ], + "Resource": "*" + } + ] +} +``` + + +## Usage + +Here are descriptions of the options passed to `AwsSsmEnv#load`. + +### decryption: [Boolean] + +Flag indicating whether to decrypt SecureString parameters. +If `true` is specified, the value of the acquired SecureString parameter is decrypted. +In case of `false` it is set as encrypted and environment variable value. +Since it is a gem for this, the default is `true` (decrypt). + +### overwrite: [Boolean] + +Specify whether to overwrite an already set environment variable. +If `true` is specified, even if the environment variable is set, +it overwrites it with the acquired parameter value. +If `false` is specified, do not overwrite already set environment variables. +The default is `false` (do not overwrite). +If you invoke `AwsSsmEnv#load!`, This flag will automatically be set to `true`. + +### client: [Aws::SSM::Client] + +Specify an instance of `Aws::SSM::Client`. +An option to set it if there are already created instances. +If there are no instances created, use `ssm_client_args` instead. + +### ssm_client_args: [Hash] + +Specify a hash to pass to the constructor of `Aws::SSM::Client`. +If not specified, `Aws::SSM::Client#new` is called with an empty argument. +It is unnecessary when using environment variable +or authentication information by `EC2 InstanceProfile`. + +### fetch: [Symbol, AwsSsmEnv::Fetcher, Object] + +Specify parameter fetch strategy. +Possible values are `:path`,`:begins_with` +or an instance of a class that implements `AwsSsmEnv::Fetcher`, +or an instance of a class with a `each` method. +If nothing is specified, it is treated as `:path`. +But when `begins_with` (which is described later) is specified, +it will automatically be `:begins_with`. + +#### `:fetch => :path` or default + +When `:path` is specified, `AwsSsmEnv::PathFetcher` which fetches +parameter hierarchy by path specification is used. +In this case, the `path` argument described below is required. +Also, the `recursive` argument (described later) is used. +When acquiring parameters in this way, you need `ssm:GetParametersByPath` authority +for the specified path. +An example of the IAM policy is shown below. + +```json +{ + "Version": "2012-10-17", + "Statement": [ + { + "Sid": "", + "Effect": "Allow", + "Action": "ssm:GetParametersByPath", + "Resource": "arn:aws:ssm:YOUR_REGION:YOUR_ACCOUNT_ID:parameter/YOUR_PATH" + } + ] +} +``` + +#### `:fetch => :begins_with` + +If `:begins_with` is specified, `AwsSsmEnv::BeginsWithFetcher` is used to fetch +parameters starting from the character string specified by the parameter name. +In this case, the `begins_with` argument described below is required. +When acquiring parameters in this way, +you need the authority of `ssm:DescribeParameters` and `ssm:GetParameters` +for the specified path. +An example of the IAM policy is shown below. + +```json +{ + "Version": "2012-10-17", + "Statement": [ + { + "Sid": "", + "Effect": "Allow", + "Action": "ssm:DescribeParameters", + "Resource": "arn:aws:ssm:YOUR_REGION:YOUR_ACCOUNT_ID:parameter" + }, + { + "Sid": "", + "Effect": "Allow", + "Action": "ssm:GetParameters", + "Resource": "arn:aws:ssm:YOUR_REGION:YOUR_ACCOUNT_ID:parameter/YOUR_PREFIX*" + } + ] +} +``` + +#### other + +If you specify an instance of a class that implements `AwsSsmEnv::Fetcher` in` fetch`, +or an instance with a `each` method, that instance will be used as is. + +### naming: [Symbol, AwsSsmEnv::NamingStrategy, Object] + +Specify the naming strategy for the environment variable name. +Possible values are `:basename`,`:snakecase` +or an instance of a class that implements `AwsSsmEnv::NamingStrategy`, +or an instance of a class with a `parse_name` method. +If nothing is specified, it is treated as `:basename`. + +#### `:naming => :basename` or default + +If `naming` is not specified or `:basename` is specified, +`AwsSsmEnv::BasenameNamingStrategy` whose variable name is +the last hierarchy of the parameter hierarchy is used. +In this case, for example, if the parameter name is `/myapp/production/DB_PASSWORD`, +the parameter value is set to `ENV['DB_PASSWORD']`. + +#### `:naming => :snakecase` + +When `:snakecase` is specified, `AwsSsmEnv::SnakeCaseNamingStrategy` which uses +the underscore delimiter of the parameter name's slash delimiter and converts +it to uppercase letters as the environment variable name is used. +In this case, for example, if the parameter name is `/myapp/production/DB_PASSWORD`, +the parameter value is set to `ENV['MYAPP_PRODUCTION_DB_PASSWORD']`. +You can specify first part of string to exclude with +the `removed_prefix` argument described below. +In addition, you can specify characters to be converted to +underscores with the `delimiter` option described below. +In the following example, the parameter `/myapp/production/db.password` is +set to `ENV['DB_PASSWORD']`. + +```ruby +AwsSsmEnv.load!( + naming: :snakecase, + removed_prefix: '/myapp/production', + delimiter: /[\/.]/ +) +``` + +#### other + +If you specify an instance of a class that implements `AwsSsmEnv::NamingStrategy` in` fetch`, +or an instance with a `parse_name` method, that instance is used as is. + + +### path: [String] + +Required if nothing is specified for `fetch` or if `:path` is specified. +This option specifies the path hierarchy for acquiring parameters from `Parameter Store`. +In the example below, the parameter immediately under `/myapp/web/production` is acquired. + +```ruby +AwsSsmEnv.load(path: '/myapp/web/production') +``` + +#### recursive: [Boolean] + +Used when no parameter is specified for `fetch` option or when `:path` is specified. +If true is specified, acquires all parameters below the specified path hierarchy. +If nothing is specified this parameter, it is treated as `false`(one level). +In the following example, all parameters below `/myapp/web/production` are acquired. + +```ruby +AwsSsmEnv.load(path: '/myapp/web/production', recursive: true) +``` + +### begins_with: [String, Array] + +Required if `:begins_with` is specified in `fetch`. +You can specify the prefix of the parameter name to be acquired by this option. +It is also possible to specify more than one in an array (OR condition). +In the example below, parameters with names starting with `myapp.web.production` are acquired. + +```ruby +AwsSsmEnv.load(path: 'myapp.web.production') +``` + +### removed_prefix: [String] + +Used when `:snakecase` is specified in `naming`. +By this option, you can specify the prefix of the parameter name to exclude +from the environment variable name. +If `:removed_ prefix` is not specified, and `:begins_with` or `:path` is specified, that will be used. + +### delimiter: [String, Regexp] + +Used when `:snakecase` is specified in `naming`. +By this option, you can specify a string or a regular expression to be converted to an underscore. +The default is a slash (`/`). + +### fetch_size: [Integer] + +Specify the number of parameters to be acquired with one execution of AWS API. +If `:path` is specified, the maximum value is `10` and the default is `10`. +If `:begins_with` is specified, the maximum value is `50` and the default is `50`. +Usually this parameter is never specified. + +## Security + +Because you must grant authority to acquire secret information, +careful attention is required for security operation. + + +When the `EC2 InstanceProfile` is set, the parameters can be seen by any account on EC2, +It is necessary to improve the security level by preparing an IAM User separately +from the `EC2 InstanceProfile`. + +If it is only the administrator that you can log in to EC2, +it is not much different from having it in a file. + +Since `AWS Fargate` makes it difficult to execute commands on containers, +this risk is mitigated. + +## License + +Apache License 2.0 + +## Contributors + +- Ryohei Sonoda <[sonodar](https://github.com/sonodar)> diff --git a/ruby/README_ja.md b/ruby/README_ja.md new file mode 100644 index 0000000..ead4ffd --- /dev/null +++ b/ruby/README_ja.md @@ -0,0 +1,322 @@ +[![Build Status](https://travis-ci.org/sonodar/aws-ssm-env-ruby.svg?branch=master)](https://travis-ci.org/sonodar/aws-ssm-env-ruby) +[![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) +[![Gem Version](https://badge.fury.io/rb/aws-ssm-env.svg)](https://badge.fury.io/rb/aws-ssm-env) + +# aws-ssm-env + +AWS EC2 Parameter Storeから取得したパラメータを環境変数として設定します。 + +デフォルトでは、パラメータ名の最後の階層が環境変数名として設定されます。 + +例えば、`/staging/secure/DB_PASSWORD`というパラメータ名であれば、`ENV['DB_PASSWORD']`にパラメータ値が設定されます。 +この環境変数のネーミングはオプションでカスタマイズ可能です。(後述) + +## Installation + +このgemはRuby2.7から3.3まででテストされています。 + +``` +gem install aws-ssm-env +``` + +### Rails + +```ruby +# Gemfile +gem 'aws-ssm-env', group: :aws +``` + +```ruby +# config/application.rb +if defined?(AwsSsmEnv) + AwsSsmEnv.load(path: "/myapp/#{ENV['RAILS_ENV']}", recursive: true) +end +``` + +### Other ruby program + +```ruby +require 'aws-ssm-env' +AwsSsmEnv.load!(begins_with: "myapp.#{ENV['RACK_ENV']}.") +``` + +## Quick Start + +事前にAWS EC2 Parameter Storeにパラメータを登録しておく必要があります。 + +```shell +# 例) /myservice/staging/RDS_PASSWORDをSecureStringで登録 +aws ssm --region ap-northeast-1 put-parameter \ + --name /myservice/staging/RDS_PASSWORD \ + --type SecureString --value +``` + +AWSの認証情報を設定します。例えば、以下のように環境変数を利用したり、 + +```shell +export AWS_ACCESS_KEY_ID=YOURACCESSKEYID +export AWS_SECRET_ACCESS_KEY=YOURSECRETKEY +bundle exec rails start +``` + +引数で`ssm_client_args`を渡したり、 + +```ruby +AwsSsmEnv.load( + fetch: "/myservice/#{ENV['RAILS_ENV']}", + ssm_client_args: { + access_key_id: 'ACCESS_KEY_ID', + secret_access_key: 'SECRET_ACCESS_KEY', + region: 'ap-northeast-1', + } +) +``` + +`Aws.config`を利用することもできます。 + +```ruby + +if defined?(AwsSsmEnv) + AWS.config({ + access_key_id: 'ACCESS_KEY_ID', + secret_access_key: 'SECRET_ACCESS_KEY', + region: 'ap-northeast-1', + }) + AwsSsmEnv.load(path: "/myservice/#{ENV['RAILS_ENV']}") +end +``` + +詳細はaws-sdkのドキュメントを参照してください。 + +## Develop + +### Unit test + +```shell +bundle exec rspec +bundle exec rubocop +``` + +### Integration test + +```shell +export AWS_ACCESS_KEY_ID=xxxx +export AWS_SECRET_ACCESS_KEY=xxxx +export AWS_REGION=xxxx +bundle exec rspec --tag integration +``` + +IAMユーザには以下の認可ポリシーが必要です。 + +```json +{ + "Version": "2012-10-17", + "Statement": [ + { + "Sid": "", + "Effect": "Allow", + "Action": [ + "ssm:PutParameter", + "ssm:DeleteParameters", + "ssm:DescribeParameters", + "ssm:GetParameters*" + ], + "Resource": "*" + } + ] +} +``` + + +## Usage + +`AwsSsmEnv#load`に渡すオプションの説明です。 + +### decryption: [Boolean] + +SecureStringのパラメータを復号化するかどうかを表すフラグ。 +`true`を指定した場合は取得したSecureStringパラメータの値は復号化されている。 +`false`の場合は暗号化されたまた環境変数値として設定される。 +なお、このためのgemなのでデフォルトは`true`(復号化する)。 + +### overwrite: [Boolean] + +すでに設定されている環境変数を上書きするかどうかを指定する。 +`true`を指定した場合、環境変数が設定されていても取得したパラメータ値で上書きする。 +`false`を指定した場合はすでに設定されている環境変数を上書きしない。 +デフォルトは`false`(上書きしない)。 +なお、`AwsSsmEnv#load!`を実行した場合、このフラグは自動的に`true`になる。 + +### client: [Aws::SSM::Client] + +`Aws::SSM::Client`のインスタンスを指定する。 +すでに生成済みのインスタンスがある場合にそれを設定するためのオプション。 +生成済みのインスタンスがない場合は`ssm_client_args`を利用する。 + +### ssm_client_args: [Hash] + +`Aws::SSM::Client`のコンストラクタに渡すハッシュを指定する。 +指定しなかった場合は引数なしで`Aws::SSM::Client.new`が呼ばれる。 +環境変数やEC2インスタンスプロファイルによる認証情報を利用する場合は不要。 + +### fetch: [Symbol, AwsSsmEnv::Fetcher, Object] + +パラメータ取得方法を指定する。 +指定可能な値は`:path`, `:begins_with`または`AwsSsmEnv::Fetcher`を実装したクラスのインスタンス、`each`メソッドを +持ったクラスのインスタンスのいずれか。 +何も指定されていない場合は`:path`として扱われるが、後述の`begins_with`が指定されていた場合は自動的に`:begins_with`となる。 + +#### `:fetch => :path` or default + +`:path`を指定した場合はパラメータ階層をパス指定で取得する`AwsSsmEnv::PathFetcher`が利用される。 +この場合は後述の`path`引数が必須となる。また、後述の`recursive`引数を利用する。 +この方法でパラメータを取得する場合は指定するパスに対して`ssm:GetParametersByPath`の権限が必要。 +以下、IAMポリシーの例を示す。 + +```json +{ + "Version": "2012-10-17", + "Statement": [ + { + "Sid": "", + "Effect": "Allow", + "Action": "ssm:GetParametersByPath", + "Resource": "arn:aws:ssm:YOUR_REGION:YOUR_ACCOUNT_ID:parameter/YOUR_PATH" + } + ] +} +``` + +#### `:fetch => :begins_with` + +`:begins_with`を指定した場合はパラメータ名が指定した文字列から開始するパラメータを取得する`AwsSsmEnv::BeginsWithFetcher`が利用される。 +この場合は後述の`begins_with`引数が必須となる。 +この方法でパラメータを取得する場合は指定するパスに対して`ssm:DescribeParameters`および`ssm:GetParameters`の権限が必要。 +以下、IAMポリシーの例を示す。 + +```json +{ + "Version": "2012-10-17", + "Statement": [ + { + "Sid": "", + "Effect": "Allow", + "Action": "ssm:DescribeParameters", + "Resource": "arn:aws:ssm:YOUR_REGION:YOUR_ACCOUNT_ID:parameter" + }, + { + "Sid": "", + "Effect": "Allow", + "Action": "ssm:GetParameters", + "Resource": "arn:aws:ssm:YOUR_REGION:YOUR_ACCOUNT_ID:parameter/YOUR_PREFIX*" + } + ] +} +``` + +#### other + +`fetch`に`AwsSsmEnv::Fetcher`を実装したクラスのインスタンス、もしくは`each`メソッドを持つインスタンスを指定した場合はそのインスタンスをそのまま利用する。 + +### naming: [Symbol, AwsSsmEnv::NamingStrategy, Object] + +環境変数名を導出方法を指定する。 +指定可能な値は`:basename`, `:snakecase`または`AwsSsmEnv::NamingStrategy`を実装したクラスのインスタンス、`parse_name`メソッドを持ったクラスのインスタンスのいずれか。 +デフォルトは`:basename`。 + +#### `:naming => :basename` or default + +`naming`を指定しなかった場合、もしくは`:basename`を指定した場合はパラメータ階層の最後の階層を変数名とする`AwsSsmEnv::BasenameNamingStrategy`が利用される。 +この場合、例えば`/myapp/production/DB_PASSWORD`というパラメータ名であれば`ENV['DB_PASSWORD']`にパラメータ値がインジェクションされる。 + +#### `:naming => :snakecase` + +`:snakecase`を指定した場合はパラメータ名のスラッシュ区切りをアンダースコア区切りにした結果を大文字に変換して環境変数名とする`AwsSsmEnv::SnakeCaseNamingStrategy`が利用される。 +この場合、例えば`/myapp/production/DB_PASSWORD`というパラメータ名であれば`ENV['MYAPP_PRODUCTION_DB_PASSWORD']`にパラメータ値がインジェクションされる。 +後述の`removed_prefix`引数で除外する先頭文字列を指定することができる。 +また、後述の`delimiter`オプションでアンダースコアに変換する文字を指定できる。 +以下の例では`/myapp/production/db.password`というパラメータが`ENV['DB_PASSWORD']`にインジェクションされる。 + +```ruby +AwsSsmEnv.load!( + naming: :snakecase, + removed_prefix: '/myapp/production', + delimiter: /[\/.]/ +) +``` + +#### other + +`AwsSsmEnv::NamingStrategy`を実装したクラスのインスタンス、もしくは`parse_name`メソッドを持つ +インスタンスを指定した場合はそのインスタンスをそのまま利用する。 + +### path: [String] + +`fetch`に何も指定していない場合、もしくは`:path`を指定した場合は必須となる。 +パラメータを取得するパス階層を指定する。 +下の例では`/myapp/web/production`直下のパラメータが取得される。 + +```ruby +AwsSsmEnv.load(path: '/myapp/web/production') +``` + +#### recursive: [Boolean] + +`fetch`に何も指定していない場合、もしくは`:path`を指定した場合に利用する。 +指定したパス階層以下のパラメータをすべて取得する。 +下の例では`/myapp/web/production`以下すべてのパラメータが取得される。 + +```ruby +AwsSsmEnv.load(path: '/myapp/web/production', recursive: true) +``` + +### begins_with: [String, Array] + +`fetch`に`:begins_with`を指定した場合は必須となる。 +取得するパラメータ名のプレフィクスを指定する。配列で複数指定することも可能(OR条件となる)。 +下の例では`myapp.web.production`で始まる名前のパラメータが取得される。 + +```ruby +AwsSsmEnv.load(path: 'myapp.web.production') +``` + +### removed_prefix: [String] + +`naming`に`:snakecase`を指定した場合に利用される。 +環境変数名から除外するパラメータ名のプレフィクスを指定する。 +`:removed_prefix`が指定されておらず、`:begins_with`もしくは`:path`が指定されていた場合はそれを利用する。 + +### delimiter: [String, Regexp] + +`naming`に`:snakecase`を指定した場合に利用される。 +アンダースコアに変換する文字列もしくは正規表現を指定する。 +デフォルトはスラッシュ(`/`)。 + +### fetch_size: [Integer] + +一度のAWS API実行で取得するパラメータ数を指定する。 `:path`指定の場合は最大値は`10`でデフォルトも`10`。 +`:begins_with`指定の場合は最大値は`50`でデフォルトも`50`である。通常このパラメータを指定することはない。 + + +## Motivation + +RailsアプリケーションをECSで起動する場合、環境変数を渡すのが面倒だったので作りました。 + +## Security + +シークレット情報を取得するための権限を付与しなければならないため、セキュリティ運用には十分な注意が必要です。 + +EC2インスタンスプロファイルが設定されていた場合、そのEC2上であればどのアカウントでもパラメータが見えるようになるため、 +EC2インスタンスプロファイルとは別にIAMユーザを用意するなどセキュリティレベルを上げる工夫が必要です。 + +EC2にログインできるのが管理者のみであればファイルで持つのと大差ありません。 + +`AWS Fargate`であればコンテナ上でコマンドの実行は困難なため、このリスクは軽減されます。 + +## License + +Apache License 2.0 + +## Contributors + +- Ryohei Sonoda <[sonodar](https://github.com/sonodar)> diff --git a/Rakefile b/ruby/Rakefile similarity index 100% rename from Rakefile rename to ruby/Rakefile diff --git a/aws-ssm-env.gemspec b/ruby/aws-ssm-env.gemspec similarity index 78% rename from aws-ssm-env.gemspec rename to ruby/aws-ssm-env.gemspec index f6f6797..89e002f 100644 --- a/aws-ssm-env.gemspec +++ b/ruby/aws-ssm-env.gemspec @@ -1,4 +1,4 @@ -require File.expand_path('../lib/aws-ssm-env/version', __FILE__) +require File.expand_path('lib/aws-ssm-env/version', __dir__) Gem::Specification.new do |spec| @@ -11,14 +11,15 @@ Gem::Specification.new do |spec| spec.email = [ 'ryohei-sonoda@m3.com' ] spec.license = 'Apache-2.0' - spec.files = `git ls-files README.md README_ja.md CHANGELOG.md LICENSE lib`.split($OUTPUT_RECORD_SEPARATOR) - spec.test_files = `git ls-files spec`.split($OUTPUT_RECORD_SEPARATOR) + spec.files = Dir.chdir(__dir__) do + Dir.glob('{lib/**/*,README.md,README_ja.md,CHANGELOG.md,LICENSE}') + end spec.require_paths = ['lib'] spec.required_ruby_version = '>= 2.7' spec.metadata = { - 'source_code_uri' => 'https://github.com/sonodar/aws-ssm-env-ruby', - 'changelog_uri' => 'https://github.com/sonodar/aws-ssm-env-ruby/tree/master/CHANGELOG.md' + 'source_code_uri' => 'https://github.com/sonodar/aws-ssm-env-ruby/tree/master/ruby', + 'changelog_uri' => 'https://github.com/sonodar/aws-ssm-env-ruby/tree/master/ruby/CHANGELOG.md' } spec.add_dependency 'aws-sdk-ssm', '~>1' diff --git a/lib/aws-ssm-env.rb b/ruby/lib/aws-ssm-env.rb similarity index 100% rename from lib/aws-ssm-env.rb rename to ruby/lib/aws-ssm-env.rb diff --git a/lib/aws-ssm-env/fetcher.rb b/ruby/lib/aws-ssm-env/fetcher.rb similarity index 100% rename from lib/aws-ssm-env/fetcher.rb rename to ruby/lib/aws-ssm-env/fetcher.rb diff --git a/lib/aws-ssm-env/fetchers/begins_with.rb b/ruby/lib/aws-ssm-env/fetchers/begins_with.rb similarity index 100% rename from lib/aws-ssm-env/fetchers/begins_with.rb rename to ruby/lib/aws-ssm-env/fetchers/begins_with.rb diff --git a/lib/aws-ssm-env/fetchers/factory.rb b/ruby/lib/aws-ssm-env/fetchers/factory.rb similarity index 100% rename from lib/aws-ssm-env/fetchers/factory.rb rename to ruby/lib/aws-ssm-env/fetchers/factory.rb diff --git a/lib/aws-ssm-env/fetchers/path.rb b/ruby/lib/aws-ssm-env/fetchers/path.rb similarity index 100% rename from lib/aws-ssm-env/fetchers/path.rb rename to ruby/lib/aws-ssm-env/fetchers/path.rb diff --git a/lib/aws-ssm-env/loader.rb b/ruby/lib/aws-ssm-env/loader.rb similarity index 100% rename from lib/aws-ssm-env/loader.rb rename to ruby/lib/aws-ssm-env/loader.rb diff --git a/lib/aws-ssm-env/naming_strategies/basename.rb b/ruby/lib/aws-ssm-env/naming_strategies/basename.rb similarity index 100% rename from lib/aws-ssm-env/naming_strategies/basename.rb rename to ruby/lib/aws-ssm-env/naming_strategies/basename.rb diff --git a/lib/aws-ssm-env/naming_strategies/factory.rb b/ruby/lib/aws-ssm-env/naming_strategies/factory.rb similarity index 100% rename from lib/aws-ssm-env/naming_strategies/factory.rb rename to ruby/lib/aws-ssm-env/naming_strategies/factory.rb diff --git a/lib/aws-ssm-env/naming_strategies/snakecase.rb b/ruby/lib/aws-ssm-env/naming_strategies/snakecase.rb similarity index 100% rename from lib/aws-ssm-env/naming_strategies/snakecase.rb rename to ruby/lib/aws-ssm-env/naming_strategies/snakecase.rb diff --git a/lib/aws-ssm-env/naming_strategy.rb b/ruby/lib/aws-ssm-env/naming_strategy.rb similarity index 100% rename from lib/aws-ssm-env/naming_strategy.rb rename to ruby/lib/aws-ssm-env/naming_strategy.rb diff --git a/lib/aws-ssm-env/version.rb b/ruby/lib/aws-ssm-env/version.rb similarity index 100% rename from lib/aws-ssm-env/version.rb rename to ruby/lib/aws-ssm-env/version.rb diff --git a/spec/aws_ssm_env/basename_naming_strategy_spec.rb b/ruby/spec/aws_ssm_env/basename_naming_strategy_spec.rb similarity index 100% rename from spec/aws_ssm_env/basename_naming_strategy_spec.rb rename to ruby/spec/aws_ssm_env/basename_naming_strategy_spec.rb diff --git a/spec/aws_ssm_env/begins_with_fetcher_spec.rb b/ruby/spec/aws_ssm_env/begins_with_fetcher_spec.rb similarity index 100% rename from spec/aws_ssm_env/begins_with_fetcher_spec.rb rename to ruby/spec/aws_ssm_env/begins_with_fetcher_spec.rb diff --git a/spec/aws_ssm_env/fetcher_factory_spec.rb b/ruby/spec/aws_ssm_env/fetcher_factory_spec.rb similarity index 100% rename from spec/aws_ssm_env/fetcher_factory_spec.rb rename to ruby/spec/aws_ssm_env/fetcher_factory_spec.rb diff --git a/spec/aws_ssm_env/fetcher_spec.rb b/ruby/spec/aws_ssm_env/fetcher_spec.rb similarity index 100% rename from spec/aws_ssm_env/fetcher_spec.rb rename to ruby/spec/aws_ssm_env/fetcher_spec.rb diff --git a/spec/aws_ssm_env/loader_spec.rb b/ruby/spec/aws_ssm_env/loader_spec.rb similarity index 100% rename from spec/aws_ssm_env/loader_spec.rb rename to ruby/spec/aws_ssm_env/loader_spec.rb diff --git a/spec/aws_ssm_env/naming_strategy_factory_spec.rb b/ruby/spec/aws_ssm_env/naming_strategy_factory_spec.rb similarity index 100% rename from spec/aws_ssm_env/naming_strategy_factory_spec.rb rename to ruby/spec/aws_ssm_env/naming_strategy_factory_spec.rb diff --git a/spec/aws_ssm_env/naming_strategy_spec.rb b/ruby/spec/aws_ssm_env/naming_strategy_spec.rb similarity index 100% rename from spec/aws_ssm_env/naming_strategy_spec.rb rename to ruby/spec/aws_ssm_env/naming_strategy_spec.rb diff --git a/spec/aws_ssm_env/parameter.rb b/ruby/spec/aws_ssm_env/parameter.rb similarity index 100% rename from spec/aws_ssm_env/parameter.rb rename to ruby/spec/aws_ssm_env/parameter.rb diff --git a/spec/aws_ssm_env/path_fetcher_spec.rb b/ruby/spec/aws_ssm_env/path_fetcher_spec.rb similarity index 100% rename from spec/aws_ssm_env/path_fetcher_spec.rb rename to ruby/spec/aws_ssm_env/path_fetcher_spec.rb diff --git a/spec/aws_ssm_env/snake_case_naming_strategy_spec.rb b/ruby/spec/aws_ssm_env/snake_case_naming_strategy_spec.rb similarity index 100% rename from spec/aws_ssm_env/snake_case_naming_strategy_spec.rb rename to ruby/spec/aws_ssm_env/snake_case_naming_strategy_spec.rb diff --git a/spec/aws_ssm_env_spec.rb b/ruby/spec/aws_ssm_env_spec.rb similarity index 100% rename from spec/aws_ssm_env_spec.rb rename to ruby/spec/aws_ssm_env_spec.rb diff --git a/spec/spec_helper.rb b/ruby/spec/spec_helper.rb similarity index 100% rename from spec/spec_helper.rb rename to ruby/spec/spec_helper.rb From 2baafc09028457d9c5297a6661484edfe8cfadbf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=9C=92=E7=94=B0=20=E4=BA=AE=E5=B9=B3?= Date: Mon, 29 Dec 2025 17:55:10 +0900 Subject: [PATCH 2/2] =?UTF-8?q?fix:=20RuboCop=E3=81=A7FactoryBot=20cop?= =?UTF-8?q?=E3=82=92=E7=84=A1=E5=8A=B9=E5=8C=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit rubocop-factory_bot 2.25.0以降でAutoCorrectプロパティの 互換性問題が発生するため、未使用のFactoryBot copを無効化 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 --- ruby/.rubocop.yml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/ruby/.rubocop.yml b/ruby/.rubocop.yml index 392e508..fccca1a 100644 --- a/ruby/.rubocop.yml +++ b/ruby/.rubocop.yml @@ -1,5 +1,9 @@ require: rubocop-rspec +# FactoryBotを使用していないため無効化 +FactoryBot: + Enabled: false + AllCops: DisplayCopNames: true NewCops: enable