Skip to content
This repository was archived by the owner on Jun 16, 2024. It is now read-only.

Commit 4348b9b

Browse files
committed
oidc provider (jwt vending only)
#58
1 parent 6b0ede6 commit 4348b9b

File tree

9 files changed

+127
-0
lines changed

9 files changed

+127
-0
lines changed

.gitignore

+2
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,8 @@
2424
# Ignore master key for decrypting credentials and more.
2525
/config/master.key
2626

27+
/tmp/oidc.key
28+
2729
/public/packs
2830
node_modules/
2931

+23
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
# Dumb OIDC implementation. Returns JWK set and metadata for AWS IAM consumption.
2+
class Api::OidcController < Api::ApplicationController
3+
def show_configuration
4+
expires_in(60, public: true, 's-maxage': 86400*365)
5+
render(json: {
6+
issuer: "https://#{request.host}",
7+
jwks_uri: "https://#{request.host}/api/oidc/jwks",
8+
response_types_supported: ["id_token"],
9+
subject_types_supported: ["public"],
10+
claims_supported: ["iss","aud","sub","jti","iat","nbf","exp"],
11+
id_token_signing_alg_values_supported:["RS256"],
12+
})
13+
end
14+
15+
def show_jwks
16+
expires_in(60, public: true, 's-maxage': 86400*365)
17+
render(json: {
18+
keys: [
19+
OidcSigningKey.public_jwk,
20+
],
21+
})
22+
end
23+
end

app/models/oidc_signing_key.rb

+27
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
module OidcSigningKey
2+
def self.pkey
3+
key = Rails.configuration.x.oidc.signing_key
4+
raise "no config.x.oidc.signing_key" unless key
5+
raise "should be RSA key" unless key.is_a?(OpenSSL::PKey::RSA)
6+
key
7+
end
8+
9+
def self.kid
10+
@kid ||= "to1x#{hash}"
11+
end
12+
13+
def self.hash
14+
@hash ||= OpenSSL::Digest.hexdigest('sha256', pkey.public_key.to_der)
15+
end
16+
17+
def self.public_jwk
18+
@jwk ||= {
19+
kid: kid,
20+
kty: 'RSA',
21+
use: "sig",
22+
alg: "RS256",
23+
n: Base64.urlsafe_encode64(pkey.public_key.n.to_s(2), padding: false),
24+
e: Base64.urlsafe_encode64(pkey.public_key.e.to_s(2), padding: false),
25+
}
26+
end
27+
end

config/application.rb

+3
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,9 @@
1414
# require "action_cable/engine"
1515
# require "rails/test_unit/railtie"
1616

17+
require 'openssl'
18+
require 'securerandom'
19+
1720
require_relative '../lib/outpost_local'
1821

1922
# Require the gems listed in Gemfile, including any gems

config/environments/development.rb

+4
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
config.x.staff_only = ENV['TAKEOUT_STAFF_ONLY'] == '1'
88
config.x.staff_only_stream = ENV['TAKEOUT_STAFF_ONLY_STREAM'] == '1'
99
config.x.chime.user_role_arn = ENV['TAKEOUT_USER_ROLE_ARN']
10+
config.x.chime.use_oidc = ENV['TAKEOUT_CHIME_USE_OIDC'] == '1'
1011
config.x.default_avatar_url = 'https://takeout.rubykaigi.org/assets/dummy-avatar.jpg'
1112
config.x.avatar_prefix = ENV['TAKEOUT_AVATAR_PREFIX']
1213
config.x.s3.public_bucket = ENV['TAKEOUT_S3_BUCKET'] || 'rk-takeout-app'
@@ -20,6 +21,9 @@
2021
config.x.control.password = ENV['TAKEOUT_CONTROL_PASSWORD']
2122
config.x.kiosk.password = ENV['TAKEOUT_KIOSK_PASSWORD']
2223

24+
config.x.oidc.signing_key = ENV['OIDC_SIGNING_KEY']&.yield_self { |der| OpenSSL::PKey::RSA.new(der.unpack1('m*'), '') } \
25+
|| (Rails.root.join('tmp', 'oidc.key').read rescue nil)&.yield_self { |pem| OpenSSL::PKey::RSA.new(pem, '') }
26+
2327
config.active_job.queue_adapter = ENV.fetch('ENABLE_SHORYUKEN', '1') == '1' ? :inline : :shoryuken
2428

2529
# In the development environment your application's code is reloaded any time

config/environments/production.rb

+3
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
config.x.avatar_prefix = ENV.fetch('TAKEOUT_AVATAR_PREFIX', nil) # TODO:
1313

1414
config.x.chime.user_role_arn = ENV.fetch('TAKEOUT_USER_ROLE_ARN')
15+
config.x.chime.use_oidc = ENV['TAKEOUT_CHIME_USE_OIDC'] == '1'
1516

1617
config.x.s3.public_bucket = ENV.fetch('TAKEOUT_S3_BUCKET')
1718
config.x.s3.public_prefix = ENV.fetch('TAKEOUT_S3_PREFIX')
@@ -20,6 +21,8 @@
2021
config.x.control.password = ENV.fetch('TAKEOUT_CONTROL_PASSWORD')
2122
config.x.kiosk.password = ENV.fetch('TAKEOUT_KIOSK_PASSWORD')
2223

24+
config.x.oidc.signing_key = ENV.fetch('OIDC_SIGNING_KEY').yield_self { |der| OpenSSL::PKey::RSA.new(der.unpack1('m*'), '') }
25+
2326
config.x.sentry.dsn = ENV['SENTRY_DSN']
2427
config.x.release_meta.commit = ENV['HEROKU_SLUG_COMMIT'] || ENV['RELEASE_COMMIT'] || Rails.root.join('REVISION').then { _1.exist? ? _1.read : nil } || 'COMMIT_UNKNOWN'
2528
config.x.release_meta.version = ENV['HEROKU_RELEASE_VERSION']

config/routes.rb

+6
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,8 @@
3939

4040
resources :avatars, only: %i(show), param: :handle
4141

42+
get '.well-known/openid-configuration' => 'api/oidc#show_configuration'
43+
4244
scope path: 'control', module: 'control' do
4345
get 'chime_users/:handle' => 'chime_users#lookup'
4446
end
@@ -84,6 +86,10 @@
8486

8587
resources :attendees, only: %i(index show update)
8688
end
89+
90+
scope path: 'oidc' do
91+
get :jwks, to: 'oidc#show_jwks'
92+
end
8793
end
8894

8995
if Rails.env.development? || ENV['TAKEOUT_ENABLE_OUTPOST_LOCAL'] == '1'

tf/cloudfront.tf

+44
Original file line numberDiff line numberDiff line change
@@ -154,6 +154,50 @@ resource "aws_cloudfront_distribution" "takeout-rk-o" {
154154
viewer_protocol_policy = "redirect-to-https"
155155
}
156156

157+
ordered_cache_behavior {
158+
path_pattern = "/.well-known/openid-configuration"
159+
allowed_methods = ["GET", "HEAD", "OPTIONS"]
160+
cached_methods = ["GET", "HEAD"]
161+
target_origin_id = "takeout-app"
162+
163+
forwarded_values {
164+
query_string = true
165+
headers = []
166+
cookies {
167+
forward = "none"
168+
}
169+
}
170+
171+
min_ttl = 0
172+
default_ttl = 0
173+
max_ttl = 31536000
174+
175+
compress = true
176+
viewer_protocol_policy = "redirect-to-https"
177+
}
178+
179+
ordered_cache_behavior {
180+
path_pattern = "/api/oidc/jwks"
181+
allowed_methods = ["GET", "HEAD", "OPTIONS"]
182+
cached_methods = ["GET", "HEAD"]
183+
target_origin_id = "takeout-app"
184+
185+
forwarded_values {
186+
query_string = true
187+
headers = []
188+
cookies {
189+
forward = "none"
190+
}
191+
}
192+
193+
min_ttl = 0
194+
default_ttl = 0
195+
max_ttl = 31536000
196+
197+
compress = true
198+
viewer_protocol_policy = "redirect-to-https"
199+
}
200+
157201
ordered_cache_behavior {
158202
path_pattern = "/api/tracks/*/chat_message_pin"
159203
allowed_methods = ["GET", "HEAD", "OPTIONS"]

tf/iam_TakeoutUser.tf

+15
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,21 @@ data "aws_iam_policy_document" "TakeoutUser-trust" {
1616
]
1717
}
1818
}
19+
statement {
20+
effect = "Allow"
21+
actions = ["sts:AssumeRoleWithWebIdentity", "sts:TagSession"]
22+
principals {
23+
type = "Federated"
24+
identifiers = [
25+
"arn:aws:iam::${local.aws_account_id}:oidc-provider/takeout.rubykaigi.org",
26+
]
27+
}
28+
condition {
29+
test = "StringEquals"
30+
variable = "takeout.rubykaigi.org:sub"
31+
values = ["takeout-app-user"]
32+
}
33+
}
1934
}
2035

2136
resource "aws_iam_role_policy" "TakeoutUser" {

0 commit comments

Comments
 (0)