lex-identity-aws 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/.github/CODEOWNERS +7 -0
- data/.github/dependabot.yml +18 -0
- data/.github/workflows/ci.yml +34 -0
- data/.gitignore +10 -0
- data/.rubocop.yml +8 -0
- data/CHANGELOG.md +18 -0
- data/CLAUDE.md +46 -0
- data/Gemfile +11 -0
- data/LICENSE +21 -0
- data/README.md +75 -0
- data/lex-identity-aws.gemspec +34 -0
- data/lib/legion/extensions/identity/aws/identity.rb +151 -0
- data/lib/legion/extensions/identity/aws/settings.rb +32 -0
- data/lib/legion/extensions/identity/aws/version.rb +11 -0
- data/lib/legion/extensions/identity/aws.rb +35 -0
- metadata +118 -0
checksums.yaml
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
---
|
|
2
|
+
SHA256:
|
|
3
|
+
metadata.gz: c40345c1b15e2e8de94ee6ce8e4a1223686c444794d5f266c40439e1140267e6
|
|
4
|
+
data.tar.gz: a92d1150ad3a709dc0a8f0ec9d9dfe66b8a0d7078cd59de7fb5cc38c860a2357
|
|
5
|
+
SHA512:
|
|
6
|
+
metadata.gz: 156198c60dce379bcfd992e5fa383cae5eb9b0d5796c5f6247c701e3366c1cf2a3e26974f1da9328c367a265e641da2d114a01c00bfc16fee39080d2677f4736
|
|
7
|
+
data.tar.gz: 4bc293f39cda7e5c5098952a7a3afa8b1aee367ec364d8450b26529f9bad6ab573dc353235c03876e583f8cae27ad2b1e96f9e26adb67ed8d798be12ed8e83a8
|
data/.github/CODEOWNERS
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
version: 2
|
|
2
|
+
updates:
|
|
3
|
+
- package-ecosystem: bundler
|
|
4
|
+
directory: /
|
|
5
|
+
schedule:
|
|
6
|
+
interval: weekly
|
|
7
|
+
day: monday
|
|
8
|
+
open-pull-requests-limit: 5
|
|
9
|
+
labels:
|
|
10
|
+
- "type:dependencies"
|
|
11
|
+
- package-ecosystem: github-actions
|
|
12
|
+
directory: /
|
|
13
|
+
schedule:
|
|
14
|
+
interval: weekly
|
|
15
|
+
day: monday
|
|
16
|
+
open-pull-requests-limit: 5
|
|
17
|
+
labels:
|
|
18
|
+
- "type:dependencies"
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
name: CI
|
|
2
|
+
on:
|
|
3
|
+
push:
|
|
4
|
+
branches: [main]
|
|
5
|
+
pull_request:
|
|
6
|
+
schedule:
|
|
7
|
+
- cron: '0 9 * * 1'
|
|
8
|
+
|
|
9
|
+
jobs:
|
|
10
|
+
ci:
|
|
11
|
+
uses: LegionIO/.github/.github/workflows/ci.yml@main
|
|
12
|
+
|
|
13
|
+
excluded-files:
|
|
14
|
+
uses: LegionIO/.github/.github/workflows/excluded-files.yml@main
|
|
15
|
+
|
|
16
|
+
security:
|
|
17
|
+
uses: LegionIO/.github/.github/workflows/security-scan.yml@main
|
|
18
|
+
|
|
19
|
+
version-changelog:
|
|
20
|
+
uses: LegionIO/.github/.github/workflows/version-changelog.yml@main
|
|
21
|
+
|
|
22
|
+
dependency-review:
|
|
23
|
+
uses: LegionIO/.github/.github/workflows/dependency-review.yml@main
|
|
24
|
+
|
|
25
|
+
stale:
|
|
26
|
+
if: github.event_name == 'schedule'
|
|
27
|
+
uses: LegionIO/.github/.github/workflows/stale.yml@main
|
|
28
|
+
|
|
29
|
+
release:
|
|
30
|
+
needs: [ci, excluded-files]
|
|
31
|
+
if: github.event_name == 'push' && github.ref == 'refs/heads/main'
|
|
32
|
+
uses: LegionIO/.github/.github/workflows/release.yml@main
|
|
33
|
+
secrets:
|
|
34
|
+
rubygems-api-key: ${{ secrets.RUBYGEMS_API_KEY }}
|
data/.gitignore
ADDED
data/.rubocop.yml
ADDED
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
inherit_gem:
|
|
2
|
+
rubocop-legion: config/lex.yml
|
|
3
|
+
|
|
4
|
+
# Identity provider modules use def self.* methods and cannot include Helpers::Lex.
|
|
5
|
+
# Direct Legion::Logging calls are the only option in this context.
|
|
6
|
+
Legion/HelperMigration/DirectLogging:
|
|
7
|
+
Exclude:
|
|
8
|
+
- 'lib/legion/extensions/identity/aws/identity.rb'
|
data/CHANGELOG.md
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
## [0.1.0] - 2026-04-07
|
|
4
|
+
|
|
5
|
+
### Added
|
|
6
|
+
|
|
7
|
+
- Initial release
|
|
8
|
+
- `Identity` module implementing the LegionIO identity provider contract
|
|
9
|
+
- `provider_type: :auth`, `facing: :machine`, `priority: 90`, `trust_weight: 100`
|
|
10
|
+
- `capabilities: [:authenticate, :credentials]`
|
|
11
|
+
- `resolve` calls STS `GetCallerIdentity` and derives `canonical_name` from the ARN role name segment
|
|
12
|
+
- `provide_token` resolves credentials via AssumeRole (when `role_arn` configured) or default chain,
|
|
13
|
+
returns a `Legion::Identity::Lease` with only `access_key_id` + region in metadata (never `secret_access_key` or `session_token`)
|
|
14
|
+
- `current_credentials` exposes the cached `Aws::Credentials` object for Phase 8 consumers via `Broker.credentials_for`
|
|
15
|
+
- `default_chain_credentials` uses an STS client to trigger the full SDK credential chain (env vars, shared creds, web identity, ECS, instance profile)
|
|
16
|
+
- `StandardError` rescue in `default_chain_credentials` to handle `Aws::EC2Metadata::RequestError` (RuntimeError) and `Aws::Errors::NoSuchProfileError`
|
|
17
|
+
- Top-level delegation methods (`provider_name`, `provider_type`, `facing`) satisfy extension registration without enabling double-resolution
|
|
18
|
+
- `Settings` module with ENV fallbacks: `AWS_REGION`, `AWS_DEFAULT_REGION`, `AWS_ROLE_ARN`, `AWS_PROFILE`
|
data/CLAUDE.md
ADDED
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
# lex-identity-aws
|
|
2
|
+
|
|
3
|
+
**Parent**: `/Users/miverso2/rubymine/legion/CLAUDE.md`
|
|
4
|
+
|
|
5
|
+
## Purpose
|
|
6
|
+
|
|
7
|
+
AWS IAM identity provider for LegionIO. Phase 6 cloud/machine provider. Resolves machine identity from STS `GetCallerIdentity` and provides session credentials via instance profile or AssumeRole.
|
|
8
|
+
|
|
9
|
+
**GitHub**: https://github.com/LegionIO/lex-identity-aws
|
|
10
|
+
**Gem**: `lex-identity-aws`
|
|
11
|
+
**Version**: 0.1.0
|
|
12
|
+
**License**: MIT
|
|
13
|
+
**Category**: `identity` (prefix match, phase 0, tier 0)
|
|
14
|
+
|
|
15
|
+
## Key Design Rules
|
|
16
|
+
|
|
17
|
+
- NEVER store `secret_access_key` or `session_token` in Lease metadata — only `access_key_id` + region + expiration
|
|
18
|
+
- Use STS client for default chain credentials (NOT `Aws::CredentialProviderChain` — internal API)
|
|
19
|
+
- Force-resolve lazy credentials with `.credentials` call
|
|
20
|
+
- Rescue `StandardError` (not just `Aws::Errors::ServiceError`) — `Aws::EC2Metadata::RequestError` is RuntimeError
|
|
21
|
+
- `canonical_name` derived from ARN role name segment (second slash-split segment)
|
|
22
|
+
- `provide_token` credential field is `access_key_id` only (non-secret identifier)
|
|
23
|
+
- Store actual `Aws::Credentials` object in `@credential_cache` — exposed via `current_credentials` for Phase 8 consumers
|
|
24
|
+
- `private_class_method` with explicit method names
|
|
25
|
+
|
|
26
|
+
## File Map
|
|
27
|
+
|
|
28
|
+
| Path | Purpose |
|
|
29
|
+
|------|---------|
|
|
30
|
+
| `lib/legion/extensions/identity/aws.rb` | Entry point — top-level module with `identity_provider?`, `remote_invocable?`, delegation methods |
|
|
31
|
+
| `lib/legion/extensions/identity/aws/identity.rb` | Provider contract: `resolve`, `provide_token`, `current_credentials`, `normalize` + private helpers |
|
|
32
|
+
| `lib/legion/extensions/identity/aws/settings.rb` | Settings module with ENV fallbacks |
|
|
33
|
+
| `lib/legion/extensions/identity/aws/version.rb` | VERSION constant |
|
|
34
|
+
| `spec/legion/extensions/identity/aws/identity_spec.rb` | Unit tests for Identity module |
|
|
35
|
+
| `spec/legion/extensions/identity/aws/settings_spec.rb` | Unit tests for Settings module |
|
|
36
|
+
|
|
37
|
+
## Dependencies
|
|
38
|
+
|
|
39
|
+
- `aws-sdk-core` >= 3.0
|
|
40
|
+
- `aws-sdk-sts` >= 1.0
|
|
41
|
+
- `legion-json` >= 1.2.1
|
|
42
|
+
- `legion-settings` >= 1.3.14
|
|
43
|
+
|
|
44
|
+
---
|
|
45
|
+
|
|
46
|
+
**Maintained By**: Matthew Iverson (@Esity)
|
data/Gemfile
ADDED
data/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Esity
|
|
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.
|
data/README.md
ADDED
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
# lex-identity-aws
|
|
2
|
+
|
|
3
|
+
AWS IAM identity provider for [LegionIO](https://github.com/LegionIO/LegionIO).
|
|
4
|
+
|
|
5
|
+
Resolves machine identity from AWS STS and provides session credentials via instance profile or AssumeRole. Part of the Phase 6 cloud/machine provider suite.
|
|
6
|
+
|
|
7
|
+
## Provider Contract
|
|
8
|
+
|
|
9
|
+
| Attribute | Value |
|
|
10
|
+
|-----------|-------|
|
|
11
|
+
| `provider_name` | `:aws` |
|
|
12
|
+
| `provider_type` | `:auth` |
|
|
13
|
+
| `facing` | `:machine` |
|
|
14
|
+
| `priority` | `90` |
|
|
15
|
+
| `trust_weight` | `100` |
|
|
16
|
+
| `capabilities` | `[:authenticate, :credentials]` |
|
|
17
|
+
|
|
18
|
+
## Usage
|
|
19
|
+
|
|
20
|
+
The provider auto-discovers via the `lex-identity-*` prefix in LegionIO's category registry and loads at phase 0 (before all other extensions).
|
|
21
|
+
|
|
22
|
+
At boot, `resolve` calls `sts.get_caller_identity` and derives a canonical name from the IAM role name segment of the ARN:
|
|
23
|
+
|
|
24
|
+
```
|
|
25
|
+
arn:aws:sts::123456789012:assumed-role/legion-worker/session -> legion-worker
|
|
26
|
+
arn:aws:iam::123456789012:role/my-role -> my-role
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
`provide_token` returns a `Legion::Identity::Lease` with `credential` set to `access_key_id` only. The full `Aws::Credentials` object (including secret and session token) is cached in memory and accessible via `Identity.current_credentials` or `Broker.credentials_for(:aws)` (Phase 8).
|
|
30
|
+
|
|
31
|
+
## Security
|
|
32
|
+
|
|
33
|
+
`secret_access_key` and `session_token` are **never** stored in Lease metadata. Lease metadata is exposed via audit logs, `/api/stats`, and Apollo. Use `Broker.credentials_for(:aws)` for full credential access.
|
|
34
|
+
|
|
35
|
+
## Credential Chain
|
|
36
|
+
|
|
37
|
+
When `role_arn` is not configured, the provider uses an STS client to trigger the full AWS SDK default credential chain:
|
|
38
|
+
|
|
39
|
+
1. Environment variables (`AWS_ACCESS_KEY_ID`, `AWS_SECRET_ACCESS_KEY`)
|
|
40
|
+
2. Shared credentials file (`~/.aws/credentials`)
|
|
41
|
+
3. Web identity token (EKS IRSA)
|
|
42
|
+
4. ECS task role
|
|
43
|
+
5. EC2 instance profile (IMDSv2)
|
|
44
|
+
|
|
45
|
+
When `role_arn` is configured, `AssumeRoleCredentials` is used instead.
|
|
46
|
+
|
|
47
|
+
## Settings
|
|
48
|
+
|
|
49
|
+
Configure via `settings.json` under `identity.aws`:
|
|
50
|
+
|
|
51
|
+
```json
|
|
52
|
+
{
|
|
53
|
+
"identity": {
|
|
54
|
+
"aws": {
|
|
55
|
+
"region": "us-east-2",
|
|
56
|
+
"role_arn": "arn:aws:iam::123456789012:role/my-role",
|
|
57
|
+
"session_duration": 3600,
|
|
58
|
+
"profile": "vault-contributor"
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
All settings fall back to ENV vars: `AWS_REGION`, `AWS_DEFAULT_REGION`, `AWS_ROLE_ARN`, `AWS_PROFILE`.
|
|
65
|
+
|
|
66
|
+
## Dependencies
|
|
67
|
+
|
|
68
|
+
- `aws-sdk-core` >= 3.0
|
|
69
|
+
- `aws-sdk-sts` >= 1.0
|
|
70
|
+
- `legion-json` >= 1.2.1
|
|
71
|
+
- `legion-settings` >= 1.3.14
|
|
72
|
+
|
|
73
|
+
## License
|
|
74
|
+
|
|
75
|
+
MIT
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative 'lib/legion/extensions/identity/aws/version'
|
|
4
|
+
|
|
5
|
+
Gem::Specification.new do |spec|
|
|
6
|
+
spec.name = 'lex-identity-aws'
|
|
7
|
+
spec.version = Legion::Extensions::Identity::Aws::VERSION
|
|
8
|
+
spec.authors = ['Esity']
|
|
9
|
+
spec.email = ['matthewdiverson@gmail.com']
|
|
10
|
+
|
|
11
|
+
spec.summary = 'LEX Identity AWS'
|
|
12
|
+
spec.description = 'LegionIO AWS IAM identity provider — resolves machine identity from STS ' \
|
|
13
|
+
'and provides session credentials via instance profile or AssumeRole'
|
|
14
|
+
spec.homepage = 'https://github.com/LegionIO/lex-identity-aws'
|
|
15
|
+
spec.license = 'MIT'
|
|
16
|
+
spec.required_ruby_version = '>= 3.4'
|
|
17
|
+
|
|
18
|
+
spec.metadata['homepage_uri'] = spec.homepage
|
|
19
|
+
spec.metadata['source_code_uri'] = 'https://github.com/LegionIO/lex-identity-aws'
|
|
20
|
+
spec.metadata['documentation_uri'] = 'https://github.com/LegionIO/lex-identity-aws'
|
|
21
|
+
spec.metadata['changelog_uri'] = 'https://github.com/LegionIO/lex-identity-aws'
|
|
22
|
+
spec.metadata['bug_tracker_uri'] = 'https://github.com/LegionIO/lex-identity-aws/issues'
|
|
23
|
+
spec.metadata['rubygems_mfa_required'] = 'true'
|
|
24
|
+
|
|
25
|
+
spec.files = Dir.chdir(File.expand_path(__dir__)) do
|
|
26
|
+
`git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
|
|
27
|
+
end
|
|
28
|
+
spec.require_paths = ['lib']
|
|
29
|
+
|
|
30
|
+
spec.add_dependency 'aws-sdk-core', '>= 3.0'
|
|
31
|
+
spec.add_dependency 'aws-sdk-sts', '>= 1.0'
|
|
32
|
+
spec.add_dependency 'legion-json', '>= 1.2.1'
|
|
33
|
+
spec.add_dependency 'legion-settings', '>= 1.3.14'
|
|
34
|
+
end
|
|
@@ -0,0 +1,151 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Legion
|
|
4
|
+
module Extensions
|
|
5
|
+
module Identity
|
|
6
|
+
module Aws
|
|
7
|
+
module Identity
|
|
8
|
+
def self.provider_name
|
|
9
|
+
:aws
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
def self.provider_type
|
|
13
|
+
:auth
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def self.facing
|
|
17
|
+
:machine
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
def self.priority
|
|
21
|
+
90
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
def self.trust_weight
|
|
25
|
+
100
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
def self.capabilities
|
|
29
|
+
%i[authenticate credentials]
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
def self.resolve(canonical_name: nil) # rubocop:disable Lint/UnusedMethodArgument
|
|
33
|
+
identity = caller_identity
|
|
34
|
+
return nil unless identity
|
|
35
|
+
|
|
36
|
+
# ARN format: arn:aws:sts::123456789012:assumed-role/role-name/session-name
|
|
37
|
+
# or: arn:aws:iam::123456789012:role/role-name
|
|
38
|
+
arn_parts = identity.arn.to_s.split('/')
|
|
39
|
+
role_name = arn_parts[1] || identity.arn.to_s.split(':').last
|
|
40
|
+
|
|
41
|
+
{
|
|
42
|
+
canonical_name: normalize(role_name),
|
|
43
|
+
kind: :machine,
|
|
44
|
+
source: :aws,
|
|
45
|
+
persistent: true,
|
|
46
|
+
groups: [],
|
|
47
|
+
metadata: {
|
|
48
|
+
account_id: identity.account,
|
|
49
|
+
arn: identity.arn,
|
|
50
|
+
user_id: identity.user_id
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
def self.provide_token
|
|
56
|
+
credentials = resolve_credentials
|
|
57
|
+
return nil unless credentials
|
|
58
|
+
|
|
59
|
+
expires_at = if credentials.respond_to?(:expiration) && credentials.expiration
|
|
60
|
+
credentials.expiration
|
|
61
|
+
else
|
|
62
|
+
Time.now + 3600
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
# Store the full credential object for Broker.credentials_for(:aws) consumers.
|
|
66
|
+
# NEVER store secret_access_key or session_token in Lease metadata —
|
|
67
|
+
# Lease#to_h is exposed via audit logs, /api/stats, and Apollo.
|
|
68
|
+
@credential_cache = credentials # rubocop:disable ThreadSafety/ClassInstanceVariable
|
|
69
|
+
|
|
70
|
+
Legion::Identity::Lease.new(
|
|
71
|
+
provider: :aws,
|
|
72
|
+
credential: credentials.access_key_id,
|
|
73
|
+
expires_at: expires_at,
|
|
74
|
+
renewable: credentials.respond_to?(:expiration),
|
|
75
|
+
issued_at: Time.now,
|
|
76
|
+
metadata: {
|
|
77
|
+
access_key_id: credentials.access_key_id,
|
|
78
|
+
region: settings[:region],
|
|
79
|
+
expiration: expires_at&.iso8601
|
|
80
|
+
}
|
|
81
|
+
)
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
def self.current_credentials
|
|
85
|
+
@credential_cache # rubocop:disable ThreadSafety/ClassInstanceVariable
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
def self.normalize(val)
|
|
89
|
+
val.to_s.downcase.strip.gsub(/[^a-z0-9_-]/, '_')
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
def self.settings
|
|
93
|
+
Legion::Extensions::Identity::Aws.settings
|
|
94
|
+
end
|
|
95
|
+
|
|
96
|
+
def self.caller_identity
|
|
97
|
+
require 'aws-sdk-sts'
|
|
98
|
+
sts = ::Aws::STS::Client.new(region: settings[:region])
|
|
99
|
+
sts.get_caller_identity
|
|
100
|
+
rescue ::Aws::Errors::ServiceError => e
|
|
101
|
+
Legion::Logging.warn("AWS STS get_caller_identity failed: #{e.message}")
|
|
102
|
+
nil
|
|
103
|
+
end
|
|
104
|
+
|
|
105
|
+
def self.resolve_credentials
|
|
106
|
+
if settings[:role_arn]
|
|
107
|
+
assume_role_credentials
|
|
108
|
+
else
|
|
109
|
+
default_chain_credentials
|
|
110
|
+
end
|
|
111
|
+
end
|
|
112
|
+
|
|
113
|
+
def self.assume_role_credentials
|
|
114
|
+
require 'aws-sdk-sts'
|
|
115
|
+
instance_id = defined?(Legion) && Legion.respond_to?(:instance_id) ? Legion.instance_id.to_s[0..7] : 'default'
|
|
116
|
+
::Aws::AssumeRoleCredentials.new(
|
|
117
|
+
client: ::Aws::STS::Client.new(region: settings[:region]),
|
|
118
|
+
role_arn: settings[:role_arn],
|
|
119
|
+
role_session_name: "legion-#{instance_id}",
|
|
120
|
+
duration_seconds: settings[:session_duration] || 3600
|
|
121
|
+
)
|
|
122
|
+
rescue ::Aws::Errors::ServiceError => e
|
|
123
|
+
Legion::Logging.warn("AWS AssumeRole failed: #{e.message}")
|
|
124
|
+
nil
|
|
125
|
+
end
|
|
126
|
+
|
|
127
|
+
def self.default_chain_credentials
|
|
128
|
+
require 'aws-sdk-core'
|
|
129
|
+
# Use an STS client to trigger the full SDK default credential chain.
|
|
130
|
+
# Aws::CredentialProviderChain is internal and not a public API.
|
|
131
|
+
# Creating an STS client triggers: env vars -> shared credentials ->
|
|
132
|
+
# web identity -> ECS task role -> instance profile (the full chain).
|
|
133
|
+
client = ::Aws::STS::Client.new(region: settings[:region])
|
|
134
|
+
creds = client.config.credentials
|
|
135
|
+
creds.credentials # force-resolve lazy credentials
|
|
136
|
+
creds
|
|
137
|
+
rescue StandardError => e
|
|
138
|
+
# Aws::EC2Metadata::RequestError is RuntimeError, not ServiceError.
|
|
139
|
+
# Aws::Errors::NoSuchProfileError for invalid AWS_PROFILE.
|
|
140
|
+
# All caught here for graceful fallback.
|
|
141
|
+
Legion::Logging.debug("AWS default chain failed: #{e.message}")
|
|
142
|
+
nil
|
|
143
|
+
end
|
|
144
|
+
|
|
145
|
+
private_class_method :caller_identity, :resolve_credentials, :assume_role_credentials,
|
|
146
|
+
:default_chain_credentials, :settings
|
|
147
|
+
end
|
|
148
|
+
end
|
|
149
|
+
end
|
|
150
|
+
end
|
|
151
|
+
end
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Legion
|
|
4
|
+
module Extensions
|
|
5
|
+
module Identity
|
|
6
|
+
module Aws
|
|
7
|
+
SETTINGS_DEFAULTS = {
|
|
8
|
+
region: nil,
|
|
9
|
+
role_arn: nil,
|
|
10
|
+
session_duration: 3600,
|
|
11
|
+
profile: nil
|
|
12
|
+
}.freeze
|
|
13
|
+
|
|
14
|
+
def self.settings
|
|
15
|
+
base = if defined?(Legion::Settings) && Legion::Settings.respond_to?(:dig)
|
|
16
|
+
Legion::Settings.dig(:identity, :aws) || {}
|
|
17
|
+
else
|
|
18
|
+
{}
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
region = ENV.fetch('AWS_REGION', nil) || ENV.fetch('AWS_DEFAULT_REGION', nil) || 'us-east-2'
|
|
22
|
+
role_arn = ENV.fetch('AWS_ROLE_ARN', nil)
|
|
23
|
+
profile = ENV.fetch('AWS_PROFILE', nil)
|
|
24
|
+
|
|
25
|
+
SETTINGS_DEFAULTS
|
|
26
|
+
.merge(region: region, role_arn: role_arn, profile: profile)
|
|
27
|
+
.merge(base)
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
end
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'legion/extensions/identity/aws/version'
|
|
4
|
+
require 'legion/extensions/identity/aws/settings'
|
|
5
|
+
require 'legion/extensions/identity/aws/identity'
|
|
6
|
+
|
|
7
|
+
module Legion
|
|
8
|
+
module Extensions
|
|
9
|
+
module Identity
|
|
10
|
+
module Aws
|
|
11
|
+
extend Legion::Extensions::Core if Legion::Extensions.const_defined?(:Core, false)
|
|
12
|
+
|
|
13
|
+
def self.identity_provider?
|
|
14
|
+
true
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def self.remote_invocable?
|
|
18
|
+
false
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def self.provider_name
|
|
22
|
+
Identity.provider_name
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def self.provider_type
|
|
26
|
+
Identity.provider_type
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
def self.facing
|
|
30
|
+
Identity.facing
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
end
|
metadata
ADDED
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
|
2
|
+
name: lex-identity-aws
|
|
3
|
+
version: !ruby/object:Gem::Version
|
|
4
|
+
version: 0.1.0
|
|
5
|
+
platform: ruby
|
|
6
|
+
authors:
|
|
7
|
+
- Esity
|
|
8
|
+
bindir: bin
|
|
9
|
+
cert_chain: []
|
|
10
|
+
date: 1980-01-02 00:00:00.000000000 Z
|
|
11
|
+
dependencies:
|
|
12
|
+
- !ruby/object:Gem::Dependency
|
|
13
|
+
name: aws-sdk-core
|
|
14
|
+
requirement: !ruby/object:Gem::Requirement
|
|
15
|
+
requirements:
|
|
16
|
+
- - ">="
|
|
17
|
+
- !ruby/object:Gem::Version
|
|
18
|
+
version: '3.0'
|
|
19
|
+
type: :runtime
|
|
20
|
+
prerelease: false
|
|
21
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
22
|
+
requirements:
|
|
23
|
+
- - ">="
|
|
24
|
+
- !ruby/object:Gem::Version
|
|
25
|
+
version: '3.0'
|
|
26
|
+
- !ruby/object:Gem::Dependency
|
|
27
|
+
name: aws-sdk-sts
|
|
28
|
+
requirement: !ruby/object:Gem::Requirement
|
|
29
|
+
requirements:
|
|
30
|
+
- - ">="
|
|
31
|
+
- !ruby/object:Gem::Version
|
|
32
|
+
version: '1.0'
|
|
33
|
+
type: :runtime
|
|
34
|
+
prerelease: false
|
|
35
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
36
|
+
requirements:
|
|
37
|
+
- - ">="
|
|
38
|
+
- !ruby/object:Gem::Version
|
|
39
|
+
version: '1.0'
|
|
40
|
+
- !ruby/object:Gem::Dependency
|
|
41
|
+
name: legion-json
|
|
42
|
+
requirement: !ruby/object:Gem::Requirement
|
|
43
|
+
requirements:
|
|
44
|
+
- - ">="
|
|
45
|
+
- !ruby/object:Gem::Version
|
|
46
|
+
version: 1.2.1
|
|
47
|
+
type: :runtime
|
|
48
|
+
prerelease: false
|
|
49
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
50
|
+
requirements:
|
|
51
|
+
- - ">="
|
|
52
|
+
- !ruby/object:Gem::Version
|
|
53
|
+
version: 1.2.1
|
|
54
|
+
- !ruby/object:Gem::Dependency
|
|
55
|
+
name: legion-settings
|
|
56
|
+
requirement: !ruby/object:Gem::Requirement
|
|
57
|
+
requirements:
|
|
58
|
+
- - ">="
|
|
59
|
+
- !ruby/object:Gem::Version
|
|
60
|
+
version: 1.3.14
|
|
61
|
+
type: :runtime
|
|
62
|
+
prerelease: false
|
|
63
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
64
|
+
requirements:
|
|
65
|
+
- - ">="
|
|
66
|
+
- !ruby/object:Gem::Version
|
|
67
|
+
version: 1.3.14
|
|
68
|
+
description: LegionIO AWS IAM identity provider — resolves machine identity from STS
|
|
69
|
+
and provides session credentials via instance profile or AssumeRole
|
|
70
|
+
email:
|
|
71
|
+
- matthewdiverson@gmail.com
|
|
72
|
+
executables: []
|
|
73
|
+
extensions: []
|
|
74
|
+
extra_rdoc_files: []
|
|
75
|
+
files:
|
|
76
|
+
- ".github/CODEOWNERS"
|
|
77
|
+
- ".github/dependabot.yml"
|
|
78
|
+
- ".github/workflows/ci.yml"
|
|
79
|
+
- ".gitignore"
|
|
80
|
+
- ".rubocop.yml"
|
|
81
|
+
- CHANGELOG.md
|
|
82
|
+
- CLAUDE.md
|
|
83
|
+
- Gemfile
|
|
84
|
+
- LICENSE
|
|
85
|
+
- README.md
|
|
86
|
+
- lex-identity-aws.gemspec
|
|
87
|
+
- lib/legion/extensions/identity/aws.rb
|
|
88
|
+
- lib/legion/extensions/identity/aws/identity.rb
|
|
89
|
+
- lib/legion/extensions/identity/aws/settings.rb
|
|
90
|
+
- lib/legion/extensions/identity/aws/version.rb
|
|
91
|
+
homepage: https://github.com/LegionIO/lex-identity-aws
|
|
92
|
+
licenses:
|
|
93
|
+
- MIT
|
|
94
|
+
metadata:
|
|
95
|
+
homepage_uri: https://github.com/LegionIO/lex-identity-aws
|
|
96
|
+
source_code_uri: https://github.com/LegionIO/lex-identity-aws
|
|
97
|
+
documentation_uri: https://github.com/LegionIO/lex-identity-aws
|
|
98
|
+
changelog_uri: https://github.com/LegionIO/lex-identity-aws
|
|
99
|
+
bug_tracker_uri: https://github.com/LegionIO/lex-identity-aws/issues
|
|
100
|
+
rubygems_mfa_required: 'true'
|
|
101
|
+
rdoc_options: []
|
|
102
|
+
require_paths:
|
|
103
|
+
- lib
|
|
104
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
|
105
|
+
requirements:
|
|
106
|
+
- - ">="
|
|
107
|
+
- !ruby/object:Gem::Version
|
|
108
|
+
version: '3.4'
|
|
109
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
110
|
+
requirements:
|
|
111
|
+
- - ">="
|
|
112
|
+
- !ruby/object:Gem::Version
|
|
113
|
+
version: '0'
|
|
114
|
+
requirements: []
|
|
115
|
+
rubygems_version: 3.6.9
|
|
116
|
+
specification_version: 4
|
|
117
|
+
summary: LEX Identity AWS
|
|
118
|
+
test_files: []
|