lambda_vault_auth 0.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (8) hide show
  1. checksums.yaml +7 -0
  2. data/Gemfile +7 -0
  3. data/LICENSE +13 -0
  4. data/README.md +99 -0
  5. data/Rakefile +10 -0
  6. data/VERSION +1 -0
  7. data/lib/lambda_vault_auth.rb +107 -0
  8. metadata +106 -0
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: b709606a9982fe1e6f8248acbb72436217e231f3d20bd6f808f963faf366a472
4
+ data.tar.gz: a1d035fc195ee1a0c62ea2e901687b71c954c013053f8199e7ecc73a985d6cd4
5
+ SHA512:
6
+ metadata.gz: bd519447ef2828f5720af18996a84dd7a9365c64c20168b2220f2cfcc31d7f072df196581c9e37daa007e0ad8277a0419288b82750e28b1cbbeb15c1f7366c8b
7
+ data.tar.gz: bf6e89e32c382c60b6b216ba5d31901af1043c757ed99e1233bc2728a50061a8a87148c51043128f3f6d34fa083e8e6800a85533b413b51196d4177096a87fa0
data/Gemfile ADDED
@@ -0,0 +1,7 @@
1
+ source "https://rubygems.org"
2
+
3
+ # Specify your gem's dependencies in lambda_vault_auth.gemspec
4
+ gemspec
5
+
6
+ gem "rake", "~> 12.0"
7
+ gem "rspec", "~> 3.0"
data/LICENSE ADDED
@@ -0,0 +1,13 @@
1
+ This work is dedicated to the public domain. No rights reserved.
2
+
3
+ I, the copyright holder of this work, hereby release it into the public
4
+ domain. This applies worldwide.
5
+
6
+ I grant any entity the right to use this work for any purpose, without
7
+ any conditions, unless such conditions are required by law.
8
+
9
+ If you require a fuller legal statement, please refer to the Creative
10
+ Commons Zero license:
11
+
12
+ http://creativecommons.org/publicdomain/zero/1.0/
13
+
@@ -0,0 +1,99 @@
1
+ # lambda_vault_auth
2
+
3
+ `lambda_vault_auth` provides a streamlined way to authenticate your Ruby AWS Lambda
4
+ function to [Hashicorp Vault](https://www.vaultproject.io).
5
+
6
+ ## Usage Example
7
+
8
+ ```ruby
9
+ require 'lambda_vault_auth'
10
+
11
+ def handler(context:, event:)
12
+ vault = LambdaVaultAuth.vault()
13
+
14
+ secrets := vault.logical.read('secrets/are/found/here')
15
+ puts "Your password is: '#{secrets.data[:password]}'"
16
+ end
17
+ ```
18
+
19
+
20
+ ## Setup
21
+
22
+ First, you'll need Vault up and running somewhere network-accessible to your
23
+ Lambda function. That's out of scope for this README, but please see the
24
+ [Vault documentation](https://www.vaultproject.io/docs/install/index.html)
25
+ for more.
26
+
27
+ Then you'll need to set up an AWS authentication provider. You may already have
28
+ one configured. If so, you can use that one or you can set up a new one just for
29
+ this purpose. You don't need to worry about backend credentials for this
30
+ authentication method. It works without any AWS credentials needing to be loaded
31
+ into Vault. Or if you do have credentials loaded they don't need to have access
32
+ to the AWS account your Lambda is running in.
33
+
34
+ To establish a new AWS authentication provider, run:
35
+
36
+ $ vault auth enable -path lambda -description "IAM auth for Lambdas" aws
37
+ Success! Enabled aws auth method at: lambda/
38
+
39
+ You will also need to set the `iam_server_id_header_value` if you wish to use
40
+ the extra layer of security (as described below):
41
+
42
+ $ vault write auth/lambda/config/client \
43
+ iam_server_id_header_value=vault.example.com
44
+
45
+ Next, you'll need to establish whatever Vault policies your Lambda will need.
46
+ See the [Vault Policies](https://www.vaultproject.io/docs/concepts/policies.html)
47
+ documentation for details.
48
+
49
+ Now you'll need to know the ARN of your Lambda execution role. You can create it
50
+ with the Lambda web console or by hand. Either way it should look something like:
51
+
52
+ arn:aws:iam::987654321098:role/service-role/MyLambdaRole
53
+
54
+ *IMPORTANT*: You must remove any non-essential path from the role ARN unless you
55
+ have configured your AWS auth provider with IAM permissions to look up roles. In
56
+ this example, `service-role/` is the path segment. So the principal ARN you will
57
+ be specifying to Vault in the next step will be:
58
+
59
+ arn:aws:iam::987654321098:role/MyLambdaRole
60
+
61
+ Now it's time to create the Vault authentication role. It can be named anything
62
+ you wish. In this case, we'll call it `my-vault-role` and make it periodic since
63
+ `lambda_vault_auth` will handle renewal automatically:
64
+
65
+ $ vault write auth/lambda/role/my-vault-role \
66
+ auth_type=iam \
67
+ period=14400 \
68
+ policies=list-of,vault-policies,separated-by-commas \
69
+ resolve_aws_unique_ids=false \
70
+ bound_iam_principal_arn=arn:aws:iam::987654321098:role/MyLambdaRole
71
+
72
+ Now you are ready to configure your Lambda.
73
+
74
+ ## Configuration
75
+
76
+ All configuration is done with environment variables:
77
+
78
+ * `VAULT_ADDR` (Required) The URL of the Vault instance, eg `https://myvault.example.com`.
79
+ * `VAULT_AUTH_PROVIDER` (Required) The relative path of the AWS authentication provider, eg `lambda` for `auth/lambda` in the example above.
80
+ * `VAULT_AUTH_ROLE` (Required) The name of the Vault role to authenticate to, eg `my-vault-role` in the example above.
81
+ * `VAULT_AUTH_HEADER` (Optional, but recommended) The value of the `X-Vault-AWS-IAM-Server-ID` HTTP header to be included in the signed STS request this code uses to authenticate. This value is often set to the URL or DNS name of the Vault server to prevent potential replay attacks.
82
+
83
+ That should be all that is required to get up and running.
84
+
85
+ ## Contributing to lambda_vault_auth
86
+
87
+ * Check out the latest master to make sure the feature hasn't been implemented or the bug hasn't been fixed yet.
88
+ * Check out the issue tracker to make sure someone already hasn't requested it and/or contributed it.
89
+ * Fork the project.
90
+ * Start a feature/bugfix branch.
91
+ * Commit and push until you are happy with your contribution.
92
+ * Make sure to add tests for it. This is important so I don't break it in a future version unintentionally.
93
+ * Please try not to mess with the Rakefile, version, or history. If you want to have your own version, or is otherwise necessary, that is fine, but please isolate to its own commit so I can cherry-pick around it.
94
+
95
+
96
+ ## License
97
+
98
+ This software is public domain. No rights are reserved. See LICENSE for more
99
+ information.
@@ -0,0 +1,10 @@
1
+ require 'rake'
2
+ require 'bundler/gem_tasks'
3
+ require 'rspec/core/rake_task'
4
+
5
+ RSpec::Core::RakeTask.new(:spec) do |t|
6
+ t.pattern = Dir.glob('spec/**/*_spec.rb')
7
+ t.rspec_opts = '--format documentation'
8
+ end
9
+
10
+ task default: :spec
data/VERSION ADDED
@@ -0,0 +1 @@
1
+ 0.0.0
@@ -0,0 +1,107 @@
1
+ require 'aws-sdk-core'
2
+ require 'vault'
3
+
4
+ # TODO: support the advanced vault header in the signature, since it gives us better security
5
+ # VAULT_AUTH_HEADER_NAME = "X-Vault-AWS-IAM-Server-ID".freeze
6
+
7
+ # LambdaVaultAuth
8
+ class LambdaVaultAuth
9
+ # Internal class for Vault interactions
10
+ class Vaulter
11
+ attr_reader :auth_provider,
12
+ :auth_role,
13
+ :auth_token,
14
+ :client,
15
+ :expiration,
16
+ :expiration_window,
17
+ :renewal_window,
18
+ :ttl
19
+
20
+ def initialize(sts = Aws::STS::Client.new, env = ENV)
21
+ @sts = sts
22
+ @client = new_client_from_environment(env)
23
+
24
+ # TODO: Make the following configurable
25
+ # Lifecycle of each token
26
+ @expiration_window = 10 # seconds
27
+
28
+ # should be at least the length of the lambda runtime
29
+ @renewal_window = 300 # seconds
30
+ end
31
+
32
+ def expired?
33
+ expiration.nil? ? true : expiration > Time.now + expiration_window
34
+ end
35
+
36
+ def should_renew?
37
+ expiration.nil? ? true : Time.now + renewal_window > expiration
38
+ end
39
+
40
+ def renewable?
41
+ auth_token&.renewable
42
+ end
43
+
44
+ def renew!
45
+ handle_token(auth_token.renew_self(ttl))
46
+ end
47
+
48
+ def new_client_from_environment(env)
49
+ addr = env.fetch('VAULT_ADDR')
50
+ # @auth_header = env.fetch('VAULT_AUTH_HEADER')
51
+ @auth_provider = env.fetch('VAULT_AUTH_PROVIDER')
52
+ @auth_role = env.fetch('VAULT_AUTH_ROLE')
53
+
54
+ Vault::Client.new(
55
+ address: addr
56
+ )
57
+ end
58
+
59
+ def authenticate!
60
+ req = @sts.get_caller_identity.context.http_request
61
+
62
+ data = {
63
+ 'iam_http_request_method': req.http_method,
64
+ 'iam_request_body': Base64.strict_encode64(req.body.read),
65
+ 'iam_request_headers': Base64.strict_encode64(req.headers.to_h.to_json),
66
+ 'iam_request_url': Base64.strict_encode64(req.endpoint.to_s),
67
+ 'role': @auth_role
68
+ }
69
+
70
+ secret = client.logical.write("auth/#{@auth_provider}/login", data)
71
+
72
+ warn secret.warnings unless secret.warnings.empty?
73
+
74
+ handle_token(secret)
75
+
76
+ # create the required data to renew/validate
77
+ # populate the token on the client and hand that to the user
78
+ end
79
+
80
+ def handle_token(secret)
81
+ @auth_token = secret.auth
82
+ @ttl = secret.lease_duration
83
+ @expiration = Time.now + ttl
84
+ @client.token = @auth_token.client_token
85
+ end
86
+ end
87
+
88
+ # LambdaVaultAuth.vault returns a wrapped vault which contains a few convenience accessors/helpers
89
+ # to help manage the lifecycle of a vault and access the credentials
90
+ def self.vault
91
+ @vault ||= Vaulter.new
92
+ @sts ||= Aws::STS::Client.new
93
+
94
+ return @vault.client unless @vault.expired?
95
+
96
+ if @vault.renewable? && @vault.should_renew?
97
+ @vault.renew!
98
+ return @vault.client
99
+ end
100
+
101
+ # Otherwise, authenticate
102
+ @vault.authenticate!
103
+
104
+ # return the vault client directly
105
+ @vault.client
106
+ end
107
+ end
metadata ADDED
@@ -0,0 +1,106 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: lambda_vault_auth
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.0
5
+ platform: ruby
6
+ authors:
7
+ - Ryan Taylor
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2020-05-13 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: aws-sdk-core
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: '3.0'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: '3.0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: vault
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '0.13'
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '0.13'
41
+ - !ruby/object:Gem::Dependency
42
+ name: bundler
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: '2.0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: '2.0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: rspec
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - "~>"
60
+ - !ruby/object:Gem::Version
61
+ version: '3.5'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - "~>"
67
+ - !ruby/object:Gem::Version
68
+ version: '3.5'
69
+ description: A library for authenticating a lambda function against Hashicorp Vault
70
+ via AWS as an authentication provider.
71
+ email: rtaylor@instructure.com
72
+ executables: []
73
+ extensions: []
74
+ extra_rdoc_files: []
75
+ files:
76
+ - Gemfile
77
+ - LICENSE
78
+ - README.md
79
+ - Rakefile
80
+ - VERSION
81
+ - lib/lambda_vault_auth.rb
82
+ homepage: http://github.com/instructure/lambda_vault_auth
83
+ licenses:
84
+ - CC0-1.0
85
+ metadata: {}
86
+ post_install_message:
87
+ rdoc_options: []
88
+ require_paths:
89
+ - lib
90
+ required_ruby_version: !ruby/object:Gem::Requirement
91
+ requirements:
92
+ - - ">="
93
+ - !ruby/object:Gem::Version
94
+ version: '0'
95
+ required_rubygems_version: !ruby/object:Gem::Requirement
96
+ requirements:
97
+ - - ">="
98
+ - !ruby/object:Gem::Version
99
+ version: '0'
100
+ requirements: []
101
+ rubygems_version: 3.1.2
102
+ signing_key:
103
+ specification_version: 4
104
+ summary: Simplify authentication between an AWS lambda function and Hashicorp Vault
105
+ via the AWS authentication provider.
106
+ test_files: []