aws-msk-iam-sasl-signer 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 ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 4c1a55e1e98d1cb058d624b31c02ecb16b661bfdf2f896e087a10bc84279e799
4
+ data.tar.gz: 52a0b1d7d1ff7cb6115551b69a4a6f396ce1682f65f855d603332026d6464783
5
+ SHA512:
6
+ metadata.gz: 452a78478ed3b6677dc3cbd047b6296310b9005bbd2d618a3a436e960621a3213342ed98c2da012fc2ab2909ff99a3d844842bf7d21501759cc20f7f0b089250
7
+ data.tar.gz: b528420b2cef1f7bc66fe81a553de226f64ba18f933c336ec902cb58224147fd85e3e82f713e5f0a422b5d8e27515decf01f1363e9e24f61a5aef4a11a8cc340
data/LICENSE.txt ADDED
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2023 bruce szalwinski
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
13
+ all 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
21
+ THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,203 @@
1
+ # aws-msk-iam-sasl-signer
2
+
3
+ [![Gem Version](https://img.shields.io/gem/v/aws-msk-iam-sasl-signer)](https://rubygems.org/gems/aws-msk-iam-sasl-signer)
4
+ [![Gem Downloads](https://img.shields.io/gem/dt/aws-msk-iam-sasl-signer)](https://www.ruby-toolbox.com/projects/aws-msk-iam-sasl-signer)
5
+ [![GitHub Workflow Status](https://img.shields.io/github/actions/workflow/status/bruce-szalwinski-he/aws-msk-iam-sasl-signer-ruby/ci.yml)](https://github.com/bruce-szalwinski-he/aws-msk-iam-sasl-signer-ruby/actions/workflows/ci.yml)
6
+ [![Code Climate maintainability](https://img.shields.io/codeclimate/maintainability/bruce-szalwinski-he/aws-msk-iam-sasl-signer-ruby)](https://codeclimate.com/github/bruce-szalwinski-he/aws-msk-iam-sasl-signer-ruby)
7
+
8
+ This is an Amazon MSK Library in Ruby.
9
+ This library provides a function to generates a base 64 encoded signed url to enable authentication/authorization with an MSK Cluster.
10
+ The signed url is generated by using your IAM credentials.
11
+
12
+ # Features
13
+
14
+ - Provides a function to generate auth token using IAM credentials from the AWS default credentials chain.
15
+ - Provides a function to generate auth token using IAM credentials from the AWS named profile.
16
+ - Provides a function to generate auth token using assumed IAM role’s credentials.
17
+
18
+ ---
19
+
20
+ - [Quick start](#quick-start)
21
+ - [Support](#support)
22
+ - [License](#license)
23
+ - [Code of conduct](#code-of-conduct)
24
+ - [Contribution guide](#contribution-guide)
25
+
26
+ # Get Started
27
+
28
+ ## Installation
29
+
30
+ To install aws-msk-iam-sasl-signer-ruby, run this command in your terminal.
31
+ This is the preferred method to install aws-msk-iam-sasl-signer-ruby, as it will always install the most recent stable release.
32
+
33
+ ```bash
34
+ gem install aws-msk-iam-sasl-signer
35
+ ```
36
+
37
+ ## Usage
38
+
39
+ ```ruby
40
+
41
+ # frozen_string_literal: true
42
+ require "aws-msk-iam-sasl-signer"
43
+ require "json"
44
+ require "rdkafka"
45
+
46
+ KAFKA_TOPIC = ENV['KAFKA_TOPIC']
47
+ KAFKA_BOOTSTRAP_SERVERS = ENV['KAFKA_BOOTSTRAP_SERVERS']
48
+
49
+ kafka_config = {
50
+ "bootstrap.servers": KAFKA_BOOTSTRAP_SERVERS,
51
+ "security.protocol": 'sasl_ssl',
52
+ "sasl.mechanisms": 'OAUTHBEARER',
53
+ "client.id": 'ruby-producer',
54
+ }
55
+
56
+ def refresh_token(client, config)
57
+ signer = AwsMskIamSaslSigner::MSKTokenProvider.new(region: 'us-east-1')
58
+ auth_token = signer.generate_auth_token
59
+
60
+ error_buffer = FFI::MemoryPointer.from_string(' ' * 256)
61
+ response = Rdkafka::Bindings.rd_kafka_oauthbearer_set_token(
62
+ client, auth_token.token, auth_token.expiration_time_ms, 'kafka-cluster', nil, 0, error_buffer, 256
63
+ )
64
+ return unless response != 0
65
+
66
+ Rdkafka::Bindings.rd_kafka_oauthbearer_set_token_failure(client,
67
+ "Failed to set token: #{error_buffer.read_string}")
68
+
69
+ end
70
+
71
+ # set the token refresh callback
72
+ Rdkafka::Config.oauthbearer_token_refresh_callback = method(:refresh_token)
73
+ producer = Rdkafka::Config.new(kafka_config).producer
74
+
75
+ # seed the token
76
+ # events_poll will invoke all registered callbacks, of which oauthbearer_token_refresh_callback is one
77
+
78
+ consumer = Rdkafka::Config.new(kafka_config).consumer
79
+ consumer.events_poll
80
+
81
+ # produce some messages
82
+
83
+ Payload = Data.define(:device_id, :creation_timestamp, :temperature)
84
+
85
+ loop do
86
+ payload = Payload.new(
87
+ device_id: '1234',
88
+ creation_timestamp: Time.now.to_i,
89
+ temperature: rand(0..100)
90
+ )
91
+
92
+ handle = producer.produce(
93
+ topic: KAFKA_TOPIC,
94
+ payload: payload.to_h.to_json,
95
+ key: "ruby-kafka-#{rand(0..999)}"
96
+ )
97
+ handle.wait(max_wait_timeout: 10)
98
+
99
+ sleep(10)
100
+ end
101
+
102
+ ```
103
+
104
+ In order to use a named profile to generate the token, replace the `generate_auth_token` function with code below:
105
+
106
+ ```ruby
107
+ signer = AwsMskIamSaslSigner::MSKTokenProvider.new(region: 'us-east-1')
108
+ auth_token = signer.generate_auth_token_from_profile(
109
+ aws_profile: 'my-profile'
110
+ )
111
+ ```
112
+
113
+
114
+ In order to use a role arn to generate the token, replace the `generate_auth_token` function with code below:
115
+
116
+ ```ruby
117
+ signer = AwsMskIamSaslSigner::MSKTokenProvider.new(region: 'us-east-1')
118
+ auth_token = signer.generate_auth_token_from_role_arn(
119
+ role_arn: 'arn:aws:iam::1234567890:role/my-role'
120
+ )
121
+ ```
122
+
123
+ In order to use a custom credentials provider, replace the `generate_auth_token` function with code below :
124
+
125
+ ```ruby
126
+ signer = AwsMskIamSaslSigner::MSKTokenProvider.new(region: 'us-east-1')
127
+ auth_token = signer.generate_auth_token_from_credentials_provider(
128
+ 'your-credentials-provider'
129
+ )
130
+ ```
131
+
132
+ ## Running tests
133
+
134
+ You can run tests in the currently configured Ruby version using `rake`.
135
+ By default, it will run all the unit tests.
136
+
137
+ ```bash
138
+ bundle exec rake test
139
+ ```
140
+
141
+ To fix lint issues, run `rubocop`.
142
+
143
+ ```bash
144
+ bundle exec rubocop -x
145
+ ```
146
+ ## Code Climate
147
+
148
+ This project uses [code climate](https://github.com/marketplace/code-climate) to maintain code quality.
149
+ Code Climate will be run on every pull request and will fail if the code quality is not maintained.
150
+ Code climate can be run locally using the command below.
151
+
152
+ ```bash
153
+ bundle exec rake codeclimate
154
+ ```
155
+
156
+ ## CLI
157
+
158
+ You can generate a signed url using the CLI.
159
+
160
+ ```bash
161
+ bundle exec signer --help
162
+ Commands:
163
+ signer generate # Generate a token using credential provider chain
164
+ signer generate-from-profile --aws-profile=AWS_PROFILE # Generate a token using aws profile
165
+ signer generate-from-role-arn --role-arn=ROLE_ARN # Generate a token using role arn
166
+ signer help [COMMAND] # Describe available commands or one specific command
167
+ ```
168
+
169
+ ## TroubleShooting
170
+
171
+ ### Finding out which identity is being used
172
+
173
+ When using the token to authenticate against an MSK cluster, you may receive an Access denied error.
174
+ There may be some doubt as to which credential is being exactly used.
175
+ The credential may be sourced from a role ARN, EC2 instance profile, credential profile etc.
176
+ When calling `generate_auth_token`, you can set `aws_debug` argument to `true`.
177
+
178
+ ```ruby
179
+ MSKAuthTokenProvider.generate_auth_token(aws_debug: true)
180
+ ```
181
+
182
+ `generate_auth_token` will return a third value, the caller identity:
183
+
184
+ ```ruby
185
+ auth_token = MSKAuthTokenProvider.generate_auth_token(aws_debug: true)
186
+ puts "Caller identity: #{auth_token.caller_identity}"
187
+ ```
188
+
189
+ ## Support
190
+
191
+ If you want to report a bug, or have ideas, feedback or questions about the gem, [let me know via GitHub issues](https://github.com/bruce-szalwinski-he/aws-msk-iam-sasl-signer-ruby/issues/new) and I will do my best to provide a helpful answer. Happy hacking!
192
+
193
+ ## License
194
+
195
+ The gem is available as open source under the terms of the [MIT License](LICENSE.txt).
196
+
197
+ ## Code of conduct
198
+
199
+ Everyone interacting in this project’s codebases, issue trackers, chat rooms and mailing lists is expected to follow the [code of conduct](CODE_OF_CONDUCT.md).
200
+
201
+ ## Contribution guide
202
+
203
+ Pull requests are welcome!
data/exe/signer ADDED
@@ -0,0 +1,4 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require "aws_msk_iam_sasl_signer"
4
+ AwsMskIamSaslSigner::CLI.start(ARGV)
@@ -0,0 +1,57 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "thor"
4
+ require "json"
5
+
6
+ module AwsMskIamSaslSigner
7
+ class CLI < Thor
8
+ extend ThorExt::Start
9
+ map %w[-v --version] => "version"
10
+ desc "version", "Display signer version", hide: true
11
+ def version
12
+ say "signer/#{VERSION} #{RUBY_DESCRIPTION}"
13
+ end
14
+
15
+ desc "generate", "Generate a token using credential provider chain"
16
+ option :region, type: :string, default: "us-east-1", desc: "The AWS region"
17
+ option :aws_debug, type: :boolean, default: false, desc: "Log caller identity when using credential provider chain"
18
+ def generate
19
+ token_provider = MSKTokenProvider.new(region: options[:region])
20
+ token = token_provider.generate_auth_token(
21
+ aws_debug: options[:aws_debug]
22
+ )
23
+
24
+ puts "Token: #{token.token}"
25
+ puts "Expiration Time: #{token.expiration_time_ms}"
26
+ return unless options[:aws_debug]
27
+
28
+ puts "Caller Identity: #{token.caller_identity.to_h.to_json}"
29
+ end
30
+
31
+ desc "generate-from-profile", "Generate a token using aws-msk-iam-sasl-signer profile"
32
+ option :region, type: :string, default: "us-east-1", desc: "The AWS region"
33
+ option :aws_profile, type: :string, desc: "Name of the AWS profile", required: true
34
+ def generate_from_profile
35
+ token_provider = MSKTokenProvider.new(region: options[:region])
36
+
37
+ signed_url, expiration_time_ms = token_provider.generate_auth_token_from_profile(options[:aws_profile])
38
+ puts "Token: #{signed_url}"
39
+ puts "Expiration Time: #{expiration_time_ms}"
40
+ end
41
+
42
+ desc "generate-from-role-arn", "Generate a token using role arn"
43
+ option :region, type: :string, default: "us-east-1", desc: "The AWS region"
44
+ option :role_arn, type: :string, desc: "ARN of the role to assume", required: true
45
+ option :session_name, type: :string, default: nil, desc: "The session name to use when assuming a role"
46
+ def generate_from_role_arn
47
+ token_provider = MSKTokenProvider.new(region: options[:region])
48
+ signed_url, expiration_time_ms = token_provider.generate_auth_token_from_role_arn(
49
+ options[:role_arn],
50
+ options[:session_name]
51
+ )
52
+
53
+ puts "Token: #{signed_url}"
54
+ puts "Expiration Time: #{expiration_time_ms}"
55
+ end
56
+ end
57
+ end
@@ -0,0 +1,23 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "aws-sigv4"
4
+
5
+ module AwsMskIamSaslSigner
6
+ class CredentialsResolver
7
+ def from_credential_provider_chain(region)
8
+ client = Aws::Kafka::Client.new(region: region)
9
+ raise "No credentials found" unless client.config.credentials
10
+
11
+ client.config.credentials
12
+ end
13
+
14
+ def from_profile(profile)
15
+ Aws::SharedCredentials.new(profile_name: profile)
16
+ end
17
+
18
+ def from_role_arn(role_arn:, session_name:)
19
+ sts = Aws::STS::Client.new
20
+ sts.assume_role({ role_arn: role_arn, role_session_name: session_name })
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,119 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "aws-sdk-kafka"
4
+ require "aws-sigv4"
5
+ require "base64"
6
+ require "uri"
7
+
8
+ module AwsMskIamSaslSigner
9
+ class MSKTokenProvider
10
+ ENDPOINT_URL_TEMPLATE = "kafka.{}.amazonaws.com"
11
+ DEFAULT_TOKEN_EXPIRY_SECONDS = 900
12
+ LIB_NAME = "aws-msk-iam-sasl-signer-msk-iam-sasl-signer-ruby"
13
+ USER_AGENT_KEY = "User-Agent"
14
+ SESSION_NAME = "MSKSASLDefaultSession"
15
+ CallerIdentity = Struct.new(:user_id, :account, :arn)
16
+ AuthToken = Struct.new(:token, :expiration_time_ms, :caller_identity)
17
+
18
+ def initialize(region:)
19
+ @region = region
20
+ end
21
+
22
+ def generate_auth_token(aws_debug: false)
23
+ credentials = CredentialsResolver.new.from_credential_provider_chain(@region)
24
+ caller_identity = caller_identity(credentials, @region) if aws_debug
25
+ url = presign(credentials, endpoint_url)
26
+ AuthToken.new(
27
+ urlsafe_encode64(user_agent(url)),
28
+ expiration_time_ms(url),
29
+ caller_identity
30
+ )
31
+ end
32
+
33
+ def generate_auth_token_from_profile(profile)
34
+ credentials = CredentialsResolver.new.from_profile(profile)
35
+ url = presign(credentials, endpoint_url)
36
+ AuthToken.new(
37
+ urlsafe_encode64(user_agent(url)),
38
+ expiration_time_ms(url)
39
+ )
40
+ end
41
+
42
+ def generate_auth_token_from_role_arn(role_arn, session_name=nil)
43
+ session_name ||= SESSION_NAME
44
+ credentials = CredentialsResolver.new.from_role_arn(
45
+ role_arn: role_arn,
46
+ session_name: session_name
47
+ )
48
+ url = presign(credentials, endpoint_url)
49
+ AuthToken.new(
50
+ urlsafe_encode64(user_agent(url)),
51
+ expiration_time_ms(url)
52
+ )
53
+ end
54
+
55
+ def generate_auth_token_from_credentials_provider(credentials_provider)
56
+ raise "Invalid credentials provider" unless credentials_provider.respond_to?(:credentials)
57
+
58
+ url = presign(credentials_provider, endpoint_url)
59
+ AuthToken.new(
60
+ urlsafe_encode64(user_agent(url)),
61
+ expiration_time_ms(url)
62
+ )
63
+ end
64
+
65
+ private
66
+
67
+ def endpoint_url
68
+ host = ENDPOINT_URL_TEMPLATE.gsub("{}", @region)
69
+ query_params = {
70
+ Action: "kafka-cluster:Connect"
71
+ }
72
+ URI::HTTPS.build(host: host, path: "/", query: URI.encode_www_form(query_params))
73
+ end
74
+
75
+ def presign(credentials_provider, url)
76
+ signer = Aws::Sigv4::Signer.new(
77
+ service: "kafka-cluster",
78
+ region: @region,
79
+ credentials_provider: credentials_provider
80
+ )
81
+ signer.presign_url(
82
+ http_method: "GET",
83
+ url: url,
84
+ expires_in: DEFAULT_TOKEN_EXPIRY_SECONDS
85
+ )
86
+ end
87
+
88
+ def user_agent(url)
89
+ new_query_ar = URI.decode_www_form(url.query) << [USER_AGENT_KEY, "#{LIB_NAME}/#{VERSION}"]
90
+ url.query = URI.encode_www_form(new_query_ar)
91
+ url.to_s
92
+ end
93
+
94
+ def urlsafe_encode64(url)
95
+ Base64.urlsafe_encode64(url, padding: false)
96
+ end
97
+
98
+ def expiration_time_ms(url)
99
+ params = URI.decode_www_form(String(url.query))
100
+ signing_date = params.find { |param| param[0] == "X-Amz-Date" }
101
+ signing_time = DateTime.strptime(signing_date[1], "%Y%m%dT%H%M%SZ")
102
+ 1000 * (signing_time.to_time.to_i + DEFAULT_TOKEN_EXPIRY_SECONDS)
103
+ end
104
+
105
+ def caller_identity(credentials_provider, region)
106
+ sts = Aws::STS::Client.new(
107
+ region: region,
108
+ access_key_id: credentials_provider.credentials.access_key_id,
109
+ secret_access_key: credentials_provider.credentials.secret_access_key,
110
+ session_token: credentials_provider.credentials.session_token
111
+ )
112
+ CallerIdentity.new(
113
+ sts.get_caller_identity.user_id,
114
+ sts.get_caller_identity.account,
115
+ sts.get_caller_identity.arn
116
+ )
117
+ end
118
+ end
119
+ end
@@ -0,0 +1,71 @@
1
+ # frozen_string_literal: true
2
+
3
+ module AwsMskIamSaslSigner
4
+ module ThorExt
5
+ # Configures Thor to behave more like a typical CLI, with better help and error handling.
6
+ #
7
+ # - Passing -h or --help to a command will show help for that command.
8
+ # - Unrecognized options will be treated as errors (instead of being silently ignored).
9
+ # - Error messages will be printed in red to stderr, without stack trace.
10
+ # - Full stack traces can be enabled by setting the VERBOSE environment variable.
11
+ # - Errors will cause Thor to exit with a non-zero status.
12
+ #
13
+ # To take advantage of this behavior, your CLI should subclass Thor and extend this module.
14
+ #
15
+ # class CLI < Thor
16
+ # extend ThorExt::Start
17
+ # end
18
+ #
19
+ # Start your CLI with:
20
+ #
21
+ # CLI.start
22
+ #
23
+ # In tests, prevent Kernel.exit from being called when an error occurs, like this:
24
+ #
25
+ # CLI.start(args, exit_on_failure: false)
26
+ #
27
+ module Start
28
+ def self.extended(base)
29
+ super
30
+ base.check_unknown_options!
31
+ end
32
+
33
+ def start(given_args=ARGV, config={})
34
+ config[:shell] ||= Thor::Base.shell.new
35
+ handle_help_switches(given_args) do |args|
36
+ dispatch(nil, args, nil, config)
37
+ end
38
+ rescue StandardError => e
39
+ handle_exception_on_start(e, config)
40
+ end
41
+
42
+ private
43
+
44
+ def handle_help_switches(given_args)
45
+ yield(given_args.dup)
46
+ rescue Thor::UnknownArgumentError => e
47
+ retry_with_args = []
48
+
49
+ if given_args.first == "help"
50
+ retry_with_args = ["help"] if given_args.length > 1
51
+ elsif (e.unknown & %w[-h --help]).any?
52
+ retry_with_args = ["help", (given_args - e.unknown).first]
53
+ end
54
+ raise unless retry_with_args.any?
55
+
56
+ yield(retry_with_args)
57
+ end
58
+
59
+ def handle_exception_on_start(error, config)
60
+ return if error.is_a?(Errno::EPIPE)
61
+ raise if ENV["VERBOSE"] || !config.fetch(:exit_on_failure, true)
62
+
63
+ message = error.message.to_s.dup
64
+ message.prepend("[#{error.class}] ") if message.empty? || !error.is_a?(Thor::Error)
65
+
66
+ config[:shell]&.say_error(message, :red)
67
+ exit(false)
68
+ end
69
+ end
70
+ end
71
+ end
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ module AwsMskIamSaslSigner
4
+ VERSION = "0.1.0"
5
+ end
@@ -0,0 +1,12 @@
1
+ require "aws-sdk-kafka"
2
+ require "aws-sigv4"
3
+ require "base64"
4
+ require "uri"
5
+
6
+ module AwsMskIamSaslSigner
7
+ autoload :MSKTokenProvider, "aws-msk-iam-sasl-signer/msk_token_provider"
8
+ autoload :CredentialsResolver, "aws-msk-iam-sasl-signer/credentials_resolver"
9
+ autoload :VERSION, "aws-msk-iam-sasl-signer/version"
10
+ autoload :CLI, "aws-msk-iam-sasl-signer/cli"
11
+ autoload :ThorExt, "aws-msk-iam-sasl-signer/thor_ext"
12
+ end
metadata ADDED
@@ -0,0 +1,86 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: aws-msk-iam-sasl-signer
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - bruce szalwinski
8
+ autorequire:
9
+ bindir: exe
10
+ cert_chain: []
11
+ date: 2024-03-04 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: aws-sdk-kafka
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: '0'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: '0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: thor
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
41
+ description:
42
+ email:
43
+ - bruce.szalwinski@hotelengine.com
44
+ executables:
45
+ - signer
46
+ extensions: []
47
+ extra_rdoc_files: []
48
+ files:
49
+ - LICENSE.txt
50
+ - README.md
51
+ - exe/signer
52
+ - lib/aws-msk-iam-sasl-signer/cli.rb
53
+ - lib/aws-msk-iam-sasl-signer/credentials_resolver.rb
54
+ - lib/aws-msk-iam-sasl-signer/msk_token_provider.rb
55
+ - lib/aws-msk-iam-sasl-signer/thor_ext.rb
56
+ - lib/aws-msk-iam-sasl-signer/version.rb
57
+ - lib/aws_msk_iam_sasl_signer.rb
58
+ homepage: https://github.com/bruce-szalwinski-he/aws-msk-iam-sasl-signer-ruby
59
+ licenses:
60
+ - MIT
61
+ metadata:
62
+ bug_tracker_uri: https://github.com/bruce-szalwinski-he/aws-msk-iam-sasl-signer-ruby/issues
63
+ changelog_uri: https://github.com/bruce-szalwinski-he/aws-msk-iam-sasl-signer-ruby/releases
64
+ source_code_uri: https://github.com/bruce-szalwinski-he/aws-msk-iam-sasl-signer-ruby
65
+ homepage_uri: https://github.com/bruce-szalwinski-he/aws-msk-iam-sasl-signer-ruby
66
+ rubygems_mfa_required: 'true'
67
+ post_install_message:
68
+ rdoc_options: []
69
+ require_paths:
70
+ - lib
71
+ required_ruby_version: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - ">="
74
+ - !ruby/object:Gem::Version
75
+ version: '3.0'
76
+ required_rubygems_version: !ruby/object:Gem::Requirement
77
+ requirements:
78
+ - - ">="
79
+ - !ruby/object:Gem::Version
80
+ version: '0'
81
+ requirements: []
82
+ rubygems_version: 3.5.3
83
+ signing_key:
84
+ specification_version: 4
85
+ summary: MSK Library in Ruby for SASL/OAUTHBEARER Auth
86
+ test_files: []