Skip to content

Commit

Permalink
feat: signer using default creds (#1)
Browse files Browse the repository at this point in the history
* signer using default creds

* pin depdendencies

* assert_equal, expected on the left

* sort by gem

* allow a and b as arg names

* rubocop

* fix trailing comma

* map to transform_values

* allow for more assertions

* no need to parse url

* remove activesupport

* remove activesupport

* add base64 because it is removed from core in 3.4

* remove unused

* aws-sdk-kafka as run time dependency

* add exe, move msk token provider to its own file

* organize like a pro

* can create token from cli

* example -> signer

* flatten

* lint

* towards aws-profile

* token from role arn

* fix abc

* cli tests

* lint

* docs

* code coverage

* show rdkafka example

* custom credential provider

* rubocop

* pass by position, rather then name

* rubocop

* screaming snake case

* rubocop

* codeclimate ignore

* codeclimate ignore

* dry

* codeclimate locally

* codeclimate

* simiplecov report

* codecoverage

* save code coverage for later

* remove unneeded

* flatten namespace

* flatten namespace

* version test

* test all of the generators

* names are hard

* found the s

* frozen

* found the s

* names are hard

* refactor

* flow

* fix typo

* let gemspec include the deps

* optionally return caller identity and let caller figure out what to do with it

* update docs

* update docs

* return a struct

* return a struct

* flatten namespace
  • Loading branch information
bruce-szalwinski-he authored Feb 29, 2024
1 parent bfa1b42 commit bef3893
Show file tree
Hide file tree
Showing 33 changed files with 786 additions and 357 deletions.
2 changes: 2 additions & 0 deletions .codeclimate.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
exclude_patterns:
- "**/thor_ext.rb"
18 changes: 18 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -28,3 +28,21 @@ jobs:
ruby-version: ${{ matrix.ruby }}
bundler-cache: true
- run: bundle exec rake test
# TODO: Add coverage reporting
# coverage:
# needs: [ test ]
# name: coverage
# runs-on: ubuntu-latest
# steps:
# - uses: actions/checkout@master
# - uses: actions/setup-node@master
# with:
# node-version: '12'
# - run: npm install -g yarn
# - run: yarn install
# - run: yarn build
# - uses: paambaati/[email protected]
# env:
# CC_TEST_REPORTER_ID: ${{ secrets.CC_TEST_REPORTER_ID }}
# with:
# coverageCommand: yarn coverage
File renamed without changes.
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -8,3 +8,5 @@
/spec/reports/
/tmp/
/Gemfile.lock
.ruby-version
.idea
12 changes: 12 additions & 0 deletions .rubocop.yml
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,9 @@ Metrics/ParameterLists:
Minitest/EmptyLineBeforeAssertionMethods:
Enabled: false

Minitest/MultipleAssertions:
Max: 20

Naming/MemoizedInstanceVariableName:
Enabled: false

Expand Down Expand Up @@ -108,3 +111,12 @@ Style/StringLiterals:

Style/TrivialAccessors:
AllowPredicates: true

inherit_mode:
merge:
- AllowedNames

Naming/MethodParameterName:
AllowedNames:
- a
- b
2 changes: 1 addition & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1 +1 @@
Release notes for this project are kept here: https://github.com/mattbrictson/gem/releases
Release notes for this project are kept here: https://github.com/bruce-szalwinski-he/aws-msk-iam-sasl-signer-ruby/releases
2 changes: 1 addition & 1 deletion CODE_OF_CONDUCT.md
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ This Code of Conduct applies within all community spaces, and also applies when

## Enforcement

Instances of abusive, harassing, or otherwise unacceptable behavior may be reported to the community leaders responsible for enforcement at owner@example.com. All complaints will be reviewed and investigated promptly and fairly.
Instances of abusive, harassing, or otherwise unacceptable behavior may be reported to the community leaders responsible for enforcement at bruce.szalwinski@hotelengine.com. All complaints will be reviewed and investigated promptly and fairly.

All community leaders are obligated to respect the privacy and security of the reporter of any incident.

Expand Down
3 changes: 3 additions & 0 deletions Gemfile
Original file line number Diff line number Diff line change
@@ -1,11 +1,14 @@
source "https://rubygems.org"
gemspec

gem "base64", "~> 0.2"
gem "minitest", "~> 5.11"
gem "minitest-rg", "~> 5.3"
gem "minitest-stub_any_instance", "~> 1.0"
gem "rake", "~> 13.0"
gem "rubocop", "1.60.2"
gem "rubocop-minitest", "0.34.5"
gem "rubocop-packaging", "0.5.2"
gem "rubocop-performance", "1.20.2"
gem "rubocop-rake", "0.6.0"
gem "simplecov", require: false, group: :test
2 changes: 1 addition & 1 deletion LICENSE.txt
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
The MIT License (MIT)

Copyright (c) 2023 Example Owner
Copyright (c) 2023 bruce szalwinski

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
Expand Down
198 changes: 168 additions & 30 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,57 +1,195 @@
# gem template
# aws-msk-iam-sasl-signer

This is a GitHub template for creating Ruby gems. Press [**Use this template**](https://github.com/mattbrictson/gem/generate) to generate a project from this template. In the generated project, run this script to rename the gem to meet your needs:
[![Gem Version](https://img.shields.io/gem/v/aws-msk-iam-sasl-signer)](https://rubygems.org/gems/aws-msk-iam-sasl-signer)
[![Gem Downloads](https://img.shields.io/gem/dt/aws-msk-iam-sasl-signer)](https://www.ruby-toolbox.com/projects/aws-msk-iam-sasl-signer)
[![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)
[![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)

This is an Amazon MSK Library in Ruby.
This library provides a function to generates a base 64 encoded signed url to enable authentication/authorization with an MSK Cluster.
The signed url is generated by using your IAM credentials.

# Features

- Provides a function to generate auth token using IAM credentials from the AWS default credentials chain.
- Provides a function to generate auth token using IAM credentials from the AWS named profile.
- Provides a function to generate auth token using assumed IAM role’s credentials.

---

- [Quick start](#quick-start)
- [Support](#support)
- [License](#license)
- [Code of conduct](#code-of-conduct)
- [Contribution guide](#contribution-guide)

# Get Started

## Installation

To install aws-msk-iam-sasl-signer-ruby, run this command in your terminal.
This is the preferred method to install aws-msk-iam-sasl-signer-ruby, as it will always install the most recent stable release.

```bash
gem install aws-msk-iam-sasl-signer
```
ruby rename_template.rb

## Usage

```ruby

# frozen_string_literal: true
require "aws-msk-iam-sasl-signer"
require "json"
require "rdkafka"

KAFKA_TOPIC = ENV['KAFKA_TOPIC']
KAFKA_BOOTSTRAP_SERVERS = ENV['KAFKA_BOOTSTRAP_SERVERS']

kafka_config = {
"bootstrap.servers": KAFKA_BOOTSTRAP_SERVERS,
"security.protocol": 'sasl_ssl',
"sasl.mechanisms": 'OAUTHBEARER',
"client.id": 'ruby-producer',
}

def refresh_token(client, config)
signer = AwsMskIamSaslSigner::MSKTokenProvider.new(region: 'us-east-1')
auth_token = signer.generate_auth_token

error_buffer = FFI::MemoryPointer.from_string(' ' * 256)
response = Rdkafka::Bindings.rd_kafka_oauthbearer_set_token(
client, auth_token.token, auth_token.expiration_time_ms, 'kafka-cluster', nil, 0, error_buffer, 256
)
return unless response != 0

Rdkafka::Bindings.rd_kafka_oauthbearer_set_token_failure(client,
"Failed to set token: #{error_buffer.read_string}")

end

# set the token refresh callback
Rdkafka::Config.oauthbearer_token_refresh_callback = method(:refresh_token)
producer = Rdkafka::Config.new(kafka_config).producer

# seed the token
# events_poll will invoke all registered callbacks, of which oauthbearer_token_refresh_callback is one

consumer = Rdkafka::Config.new(kafka_config).consumer
consumer.events_poll

# produce some messages

Payload = Data.define(:device_id, :creation_timestamp, :temperature)

loop do
payload = Payload.new(
device_id: '1234',
creation_timestamp: Time.now.to_i,
temperature: rand(0..100)
)

handle = producer.produce(
topic: KAFKA_TOPIC,
payload: payload.to_h.to_json,
key: "ruby-kafka-#{rand(0..999)}"
)
handle.wait(max_wait_timeout: 10)

sleep(10)
end

```

Note that to get the full benefits of the script, you will need the [gh](https://github.com/cli/cli) command installed.
In order to use a named profile to generate the token, replace the `generate_auth_token` function with code below:

This template is based on `bundle gem` with some notable improvements:
```ruby
signer = AwsMskIamSaslSigner::MSKTokenProvider.new(region: 'us-east-1')
auth_token = signer.generate_auth_token_from_profile(
aws_profile: 'my-profile'
)
```

- GitHub Actions configuration
- Minitest, with minitest-rg for nicely formatted test output
- Rubocop with a good set of configuration
- CLI scaffolding, built on top of Thor (optional; for more background, read [Fixing Thor’s CLI Quirks](https://mattbrictson.com/blog/fixing-thor-cli-behavior))
- [release-drafter](https://github.com/apps/release-drafter) GitHub Action for automating release notes
- A `rake bump` task to keep your Ruby and Bundler dependencies up to date
- A nice README with badges ready to go (see below)

---
In order to use a role arn to generate the token, replace the `generate_auth_token` function with code below:

<!-- END FRONT MATTER -->
```ruby
signer = AwsMskIamSaslSigner::MSKTokenProvider.new(region: 'us-east-1')
auth_token = signer.generate_auth_token_from_role_arn(
role_arn: 'arn:aws:iam::1234567890:role/my-role'
)
```

# example
In order to use a custom credentials provider, replace the `generate_auth_token` function with code below :

[![Gem Version](https://img.shields.io/gem/v/replace_with_gem_name)](https://rubygems.org/gems/replace_with_gem_name)
[![Gem Downloads](https://img.shields.io/gem/dt/replace_with_gem_name)](https://www.ruby-toolbox.com/projects/replace_with_gem_name)
[![GitHub Workflow Status](https://img.shields.io/github/actions/workflow/status/mattbrictson/gem/ci.yml)](https://github.com/mattbrictson/gem/actions/workflows/ci.yml)
[![Code Climate maintainability](https://img.shields.io/codeclimate/maintainability/mattbrictson/gem)](https://codeclimate.com/github/mattbrictson/gem)
```ruby
signer = AwsMskIamSaslSigner::MSKTokenProvider.new(region: 'us-east-1')
auth_token = signer.generate_auth_token_from_credentials_provider(
'your-credentials-provider'
)
```

TODO: Description of this gem goes here.
## Running tests

---
You can run tests in the currently configured Ruby version using `rake`.
By default, it will run all the unit tests.

- [Quick start](#quick-start)
- [Support](#support)
- [License](#license)
- [Code of conduct](#code-of-conduct)
- [Contribution guide](#contribution-guide)
```bash
bundle exec rake test
```

To fix lint issues, run `rubocop`.

```bash
bundle exec rubocop -x
```
## Code Climate

This project uses [code climate](https://github.com/marketplace/code-climate) to maintain code quality.
Code Climate will be run on every pull request and will fail if the code quality is not maintained.
Code climate can be run locally using the commands below.

```bash
brew tap codeclimate/formulae
brew install codeclimate
bundle exec rake code_climate

## Quick start
## CLI

You can generate a signed url using the CLI.

```bash
bundle exec signer --help
Commands:
signer generate # Generate a token using credential provider chain
signer generate-from-profile --aws-profile=AWS_PROFILE # Generate a token using aws profile
signer generate-from-role-arn --role-arn=ROLE_ARN # Generate a token using role arn
signer help [COMMAND] # Describe available commands or one specific command
```
gem install example

## TroubleShooting

### Finding out which identity is being used

When using the token to authenticate against an MSK cluster, you may receive an Access denied error.
There may be some doubt as to which credential is being exactly used.
The credential may be sourced from a role ARN, EC2 instance profile, credential profile etc.
When calling `generate_auth_token`, you can set `aws_debug` argument to `true`.

```ruby
MSKAuthTokenProvider.generate_auth_token(aws_debug: true)
```

`generate_auth_token` will return a third value, the caller identity:

```ruby
require "example"
auth_token = MSKAuthTokenProvider.generate_auth_token(aws_debug: true)
puts "Caller identity: #{auth_token.caller_identity}"
```

## Support

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/mattbrictson/gem/issues/new) and I will do my best to provide a helpful answer. Happy hacking!
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!

## License

Expand Down
27 changes: 23 additions & 4 deletions Rakefile
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,29 @@ RuboCop::RakeTask.new

task default: %i[test rubocop]

# task :code_climate do
# sh "docker",
# "run",
# "--interactive",
# "--tty",
# "--rm",
# "--env",
# "CODECLIMATE_CODE=$(pwd)",
# "--volume",
# "$(pwd):/code",
# "--volume",
# "/var/run/docker.sock:/var/run/docker.sock",
# "--volume",
# "/tmp/cc:/tmp/cc",
# "codeclimate/codeclimate",
# "analyze"
# end

# == "rake release" enhancements ==============================================

Rake::Task["release"].enhance do
puts "Don't forget to publish the release on GitHub!"
system "open https://github.com/mattbrictson/gem/releases"
system "open https://github.com/bruce-szalwinski-he/aws-msk-iam-sasl-signer-ruby/releases"
end

task :disable_overcommit do
Expand All @@ -27,13 +45,13 @@ Rake::Task[:build].enhance [:disable_overcommit]

task :verify_gemspec_files do
git_files = `git ls-files -z`.split("\x0")
gemspec_files = Gem::Specification.load("example.gemspec").files.sort
gemspec_files = Gem::Specification.load("aws-msk-iam-sasl-signer.gemspec").files.sort
ignored_by_git = gemspec_files - git_files
next if ignored_by_git.empty?

raise <<~ERROR
The `spec.files` specified in example.gemspec include the following files
The `spec.files` specified in aws-msk-iam-sasl-signer.gemspec include the following files
that are being ignored by git. Did you forget to add them to the repo? If
not, you may need to delete these files or modify the gemspec to ensure
that they are not included in the gem by mistake:
Expand All @@ -55,7 +73,8 @@ namespace :bump do
end

task :ruby do
replace_in_file "example.gemspec", /ruby_version = .*">= (.*)"/ => RubyVersions.lowest
replace_in_file "aws-msk-iam-sasl-signer.gemspec",
/ruby_version = .*">= (.*)"/ => RubyVersions.lowest
replace_in_file ".rubocop.yml", /TargetRubyVersion: (.*)/ => RubyVersions.lowest
replace_in_file ".github/workflows/ci.yml", /ruby: (\[.+\])/ => RubyVersions.all.inspect
end
Expand Down
Loading

0 comments on commit bef3893

Please sign in to comment.