From 7de77924dbe7e33c048f726b3326d926db4c7c2c Mon Sep 17 00:00:00 2001 From: Kevin Upstill Date: Fri, 1 May 2026 11:15:05 +0100 Subject: [PATCH 1/2] update aws-client to use credentials via aws chaining --- .github/workflows/gem-build.yml | 2 +- .github/workflows/gem-push.yml | 2 +- .github/workflows/gem-test.yml | 2 +- .rubocop.yml | 2 +- .ruby-version | 2 +- .tool-versions | 2 +- CHANGELOG.md | 13 +++++++--- Gemfile | 6 ++--- README.md | 44 +++++++++++++++++++++++++++++---- dvla-kaping.gemspec | 8 +++--- lib/dvla/kaping/aws_client.rb | 37 ++++++++++++++++++--------- lib/dvla/kaping/version.rb | 2 +- 12 files changed, 87 insertions(+), 35 deletions(-) diff --git a/.github/workflows/gem-build.yml b/.github/workflows/gem-build.yml index 33a4bf8..ad1dd79 100644 --- a/.github/workflows/gem-build.yml +++ b/.github/workflows/gem-build.yml @@ -11,7 +11,7 @@ jobs: runs-on: ubuntu-latest strategy: matrix: - ruby-version: ['3.3', '3.4'] + ruby-version: ['3.3', '3.4', '4.0'] steps: - uses: actions/checkout@v4 diff --git a/.github/workflows/gem-push.yml b/.github/workflows/gem-push.yml index 8812097..b7fa515 100644 --- a/.github/workflows/gem-push.yml +++ b/.github/workflows/gem-push.yml @@ -9,7 +9,7 @@ jobs: runs-on: ubuntu-latest strategy: matrix: - ruby-version: ['3.3', '3.4' ] + ruby-version: ['3.3', '3.4', '4.0'] steps: - uses: actions/checkout@v2 diff --git a/.github/workflows/gem-test.yml b/.github/workflows/gem-test.yml index c9790b7..955cb4c 100644 --- a/.github/workflows/gem-test.yml +++ b/.github/workflows/gem-test.yml @@ -9,7 +9,7 @@ jobs: runs-on: ubuntu-latest strategy: matrix: - ruby-version: ['3.3', '3.4' ] + ruby-version: ['3.3', '3.4', '4.0' ] steps: - uses: actions/checkout@v2 diff --git a/.rubocop.yml b/.rubocop.yml index 34fb24b..d66e09e 100644 --- a/.rubocop.yml +++ b/.rubocop.yml @@ -2,7 +2,7 @@ inherit_gem: dvla-lint: ".rubocop.yml" AllCops: - TargetRubyVersion: 3.0 + TargetRubyVersion: 4.0 Style/StringLiterals: EnforcedStyle: single_quotes diff --git a/.ruby-version b/.ruby-version index 81f1b89..4bac418 100644 --- a/.ruby-version +++ b/.ruby-version @@ -1 +1 @@ -3.4.7 \ No newline at end of file +4.0.2 \ No newline at end of file diff --git a/.tool-versions b/.tool-versions index 3f03c7a..0f1e605 100644 --- a/.tool-versions +++ b/.tool-versions @@ -1 +1 @@ -ruby 3.4.7 +ruby 4.0.2 diff --git a/CHANGELOG.md b/CHANGELOG.md index 31492f0..f3267d3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,14 +1,19 @@ ## [Unreleased] -## [1.0.2] - 2024-11-07 +## [1.0.5] - 2025-11-10 -- Initial release +- Fixed AWS credential handling to return proper credentials from assume role +- Added AWS credential chain and SSO documentation to README + +## [1.0.4] - 2025-11-10 + +- Update gems and fixed issue with git actions ## [1.0.3] - 2025-09-03 - Moved runtime dependencies to the gemspec -## [1.0.4] - 2025-11-10 +## [1.0.2] - 2024-11-07 -- Update gems and fixed issue with git actions +- Initial release diff --git a/Gemfile b/Gemfile index 1f628a7..3ecc461 100644 --- a/Gemfile +++ b/Gemfile @@ -5,11 +5,11 @@ source 'https://rubygems.org' # Specify your gem's dependencies in dvla-kaping.gemspec gemspec -gem 'bundler-audit', '~> 0.9.2' -gem 'dvla-lint', '~> 1.8' +gem 'bundler-audit', '~> 0.9.3' +gem 'dvla-lint', '~> 1.10' gem 'rake', '~> 13.0' gem 'rspec', '~> 3.0' gem 'rspec-sonarqube-formatter', '~> 1.5' -gem 'rubocop', require: false +gem 'rubocop', '~> 1.86', require: false gem 'simplecov', '~> 0.22' gem 'simplecov-console', '~> 0.9' diff --git a/README.md b/README.md index 18ce01a..e9415eb 100644 --- a/README.md +++ b/README.md @@ -74,18 +74,52 @@ kaping: ``` If you want to use the built-in client, and your OpenSearch instance is hosted in a Amazon VPC you will need to assume AWS permissions for access to run the queries. -there are two options, you can either use profile or environment +There are two options, you can either use profile or environment -Profile will just pick up the credentials save in your specified shared credentials ini file at ~/.aws/credentials, +Profile will just pick up the credentials saved in your specified shared credentials ini file at ~/.aws/credentials, ```yml aws: - # to use an AWS profile config file then set to profile, otherwise environment settings will be used - credential_type: profile + # to use an AWS profile config file, then set to profile, otherwise environment settings will be used + credential_type: profile | env | credentials account_id: ########## + role: ROLE region: aws-region profile: PROFILE - role: ROLE + +``` + +### AWS Credential Chain + +The gem supports three credential strategies: + +| credential_type | How it works | +|---|---| +| `profile` | Uses the named profile from `~/.aws/config` to create an STS client, then assumes the configured role. Supports SSO profiles. | +| `env` | Uses environment variables (`AWS_ACCESS_KEY_ID`, `AWS_SECRET_ACCESS_KEY`, or `AWS_PROFILE`) to create an STS client, then assumes the configured role. | +| `credentials` | Delegates to the AWS SDK default credential provider chain, which walks through env vars → shared config/credentials → SSO → ECS/EC2 instance roles in order. No role assumption is performed. | + +### Using AWS SSO + +If your organisation uses AWS IAM Identity Center (SSO), authenticate first then set the profile: + +```bash +aws sso login --profile my-sso-profile +``` + +Then either: +- Set `credential_type: profile` and `profile: my-sso-profile` in your `kaping.yml` +- Or set `credential_type: env` / `credentials` and export `AWS_PROFILE=my-sso-profile` + +The SDK will resolve the cached SSO token automatically. Ensure your `~/.aws/config` has the SSO profile configured, for example: + +```ini +[profile my-sso-profile] +sso_start_url = https://my-org.awsapps.com/start +sso_region = eu-west-2 +sso_account_id = 123456789012 +sso_role_name = MyRole +region = eu-west-2 ``` ## Client diff --git a/dvla-kaping.gemspec b/dvla-kaping.gemspec index a6c9273..44e09d9 100644 --- a/dvla-kaping.gemspec +++ b/dvla-kaping.gemspec @@ -13,7 +13,7 @@ Gem::Specification.new do |spec| spec.summary = 'Idiomatic way to create DSL openSearch definitions' spec.description = 'Wrapper for the AWS elastic search API to create an idiomatic way to build complex search queries' spec.homepage = 'https://github.com/dvla/kaping' - spec.required_ruby_version = '>= 3' + spec.required_ruby_version = '>= 4' spec.license = 'MIT' spec.metadata['homepage_uri'] = spec.homepage @@ -34,7 +34,7 @@ Gem::Specification.new do |spec| spec.require_paths = %w[lib] spec.add_dependency 'aws-sdk-sts', '~> 1.12' - spec.add_dependency 'aws-sigv4', '~> 1.8' - spec.add_dependency 'nokogiri', '~> 1.18', '>= 1.18.8' - spec.add_dependency 'opensearch-aws-sigv4', '~> 1.2', '>= 1.2.1' + spec.add_dependency 'aws-sigv4', '~> 1.12' + spec.add_dependency 'nokogiri', '~> 1.19' + spec.add_dependency 'opensearch-aws-sigv4', '~> 1.3' end diff --git a/lib/dvla/kaping/aws_client.rb b/lib/dvla/kaping/aws_client.rb index 15db6a9..7c32716 100644 --- a/lib/dvla/kaping/aws_client.rb +++ b/lib/dvla/kaping/aws_client.rb @@ -11,25 +11,34 @@ def initialize @base_url = Kaping.yaml[:kaping_host] @aws_account_id = Kaping.yaml.dig(:aws, :account_id) @role = Kaping.yaml.dig(:aws, :role) - @region = Kaping.yaml.dig(:aws, :region) - Kaping.logger.info { "Kaping Client | base_url: '#{@base_url}'" } + @region = Kaping.yaml.dig(:aws, :region) || 'eu-west-2' + Kaping.logger.debug { "AWS Client | base_url: '#{@base_url}'" } + end + + def select_credentials + case Kaping.yaml.dig(:aws, :credential_type) + when 'profile' + assume_role_profile(@aws_account_id, @role) + when 'env' + assume_role_env(@aws_account_id, @role) + when 'credentials' + Aws::CredentialProviderChain.new.resolve + else + logger.warn { 'Credential type not recognised, please set an option: profile, env or credentials' } + end end def connect - credentials = if Kaping.yaml.dig(:aws, :credential_type) == 'profile' - assume_role_profile(@aws_account_id, @role) - else - assume_role_env(@aws_account_id, @role) - end + credentials = select_credentials signer = Aws::Sigv4::Signer.new(service: 'es', region: @region, credentials_provider: credentials) OpenSearch::Aws::Sigv4Client.new({ - host: @base_url, - log: false, - }, signer) + host: @base_url, + log: false, + }, signer) end private @@ -38,7 +47,9 @@ def connect def assume_role_profile(aws_account_id, role) role_arn = "arn:aws:iam::#{aws_account_id}:role/#{role}" sts = Aws::STS::Client.new(region: @region, profile: Kaping.yaml.dig(:aws, :profile)) - sts.assume_role(role_arn: role_arn, role_session_name: 'kaping') + resp = sts.assume_role(role_arn: role_arn, role_session_name: 'kaping') + Aws::Credentials.new(resp.credentials.access_key_id, resp.credentials.secret_access_key, + resp.credentials.session_token) rescue Aws::STS::Errors::ServiceError => e raise "#{__method__}: AWS Profile Credentials Issue: #{e.message} #{e.class.name}" end @@ -47,7 +58,9 @@ def assume_role_profile(aws_account_id, role) def assume_role_env(aws_account_id, role) role_arn = "arn:aws:iam::#{aws_account_id}:role/#{role}" sts = Aws::STS::Client.new(region: @region) - sts.assume_role(role_arn: role_arn, role_session_name: 'kaping') + resp = sts.assume_role(role_arn: role_arn, role_session_name: 'kaping') + Aws::Credentials.new(resp.credentials.access_key_id, resp.credentials.secret_access_key, + resp.credentials.session_token) rescue Aws::STS::Errors::ServiceError => e raise "#{__method__}: AWS ENV Credentials Issue: #{e.message} #{e.class.name}" end diff --git a/lib/dvla/kaping/version.rb b/lib/dvla/kaping/version.rb index b989eb3..d223fc3 100644 --- a/lib/dvla/kaping/version.rb +++ b/lib/dvla/kaping/version.rb @@ -2,6 +2,6 @@ module DVLA module Kaping - VERSION = '1.0.4' + VERSION = '1.0.5' end end From 2a7138ff99008f263fc11f899fb351b16ce6470c Mon Sep 17 00:00:00 2001 From: Kevin Upstill Date: Fri, 1 May 2026 11:22:41 +0100 Subject: [PATCH 2/2] workflows only target ruby version 4 --- .github/workflows/gem-build.yml | 2 +- .github/workflows/gem-push.yml | 4 ++-- .github/workflows/gem-test.yml | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/gem-build.yml b/.github/workflows/gem-build.yml index ad1dd79..84a3219 100644 --- a/.github/workflows/gem-build.yml +++ b/.github/workflows/gem-build.yml @@ -11,7 +11,7 @@ jobs: runs-on: ubuntu-latest strategy: matrix: - ruby-version: ['3.3', '3.4', '4.0'] + ruby-version: ['4.0'] steps: - uses: actions/checkout@v4 diff --git a/.github/workflows/gem-push.yml b/.github/workflows/gem-push.yml index b7fa515..8fd6c5a 100644 --- a/.github/workflows/gem-push.yml +++ b/.github/workflows/gem-push.yml @@ -9,7 +9,7 @@ jobs: runs-on: ubuntu-latest strategy: matrix: - ruby-version: ['3.3', '3.4', '4.0'] + ruby-version: ['4.0'] steps: - uses: actions/checkout@v2 @@ -33,7 +33,7 @@ jobs: - name: Set up Ruby 3.4.2 uses: ruby/setup-ruby@v1 with: - ruby-version: 3.4.2 + ruby-version: 4.0.2 bundler-cache: true - name: Publish to RubyGems diff --git a/.github/workflows/gem-test.yml b/.github/workflows/gem-test.yml index 955cb4c..9268ec8 100644 --- a/.github/workflows/gem-test.yml +++ b/.github/workflows/gem-test.yml @@ -9,7 +9,7 @@ jobs: runs-on: ubuntu-latest strategy: matrix: - ruby-version: ['3.3', '3.4', '4.0' ] + ruby-version: ['4.0'] steps: - uses: actions/checkout@v2