Skip to content

Commit

Permalink
Implement user.exec auth support (#114)
Browse files Browse the repository at this point in the history
  • Loading branch information
jakolehm committed May 2, 2019
1 parent c42f28c commit 14d4999
Show file tree
Hide file tree
Showing 4 changed files with 104 additions and 9 deletions.
10 changes: 9 additions & 1 deletion lib/k8s/config.rb
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,14 @@ class UserAuthProvider < ConfigStruct
attribute :config, Types::Strict::Hash
end

# structured user exec
class UserExec < ConfigStruct
attribute :command, Types::String
attribute :apiVersion, Types::String
attribute :env, Types::Strict::Array.of(Types::Hash).optional.default(nil)
attribute :args, Types::Strict::Array.of(Types::String).optional.default(nil)
end

# structured user
class User < ConfigStruct
attribute :client_certificate, Types::String.optional.default(nil)
Expand All @@ -63,7 +71,7 @@ class User < ConfigStruct
attribute :username, Types::String.optional.default(nil)
attribute :password, Types::String.optional.default(nil)
attribute :auth_provider, UserAuthProvider.optional.default(nil)
attribute :exec, Types::Strict::Hash.optional.default(nil)
attribute :exec, UserExec.optional.default(nil)
attribute :extensions, Types::Strict::Array.optional.default(nil)
end

Expand Down
41 changes: 33 additions & 8 deletions lib/k8s/transport.rb
Original file line number Diff line number Diff line change
Expand Up @@ -75,14 +75,10 @@ def self.config(config, server: nil, **overrides)
options[:auth_token] = token
elsif config.user.auth_provider && auth_provider = config.user.auth_provider.config
logger.debug "Using config with .user.auth-provider.name=#{config.user.auth_provider.name}"

auth_data = `#{auth_provider['cmd-path']} #{auth_provider['cmd-args']}`.strip
if auth_provider['token-key']
json_path = JsonPath.new(auth_provider['token-key'][1...-1])
options[:auth_token] = json_path.first(auth_data)
else
options[:auth_token] = auth_data
end
options[:auth_token] = token_from_auth_provider(auth_provider)
elsif exec_conf = config.user.exec
logger.debug "Using config with .user.exec.command=#{exec_conf.command}"
options[:auth_token] = token_from_exec(exec_conf)
elsif config.user.username && config.user.password
logger.debug "Using config with .user.password=..."

Expand All @@ -95,6 +91,35 @@ def self.config(config, server: nil, **overrides)
new(server, **options, **overrides)
end

# @param auth_provider [K8s::Config::UserAuthProvider]
# @return [String]
def self.token_from_auth_provider(auth_provider)
auth_data = `#{auth_provider['cmd-path']} #{auth_provider['cmd-args']}`.strip
if auth_provider['token-key']
json_path = JsonPath.new(auth_provider['token-key'][1...-1])
json_path.first(auth_data)
else
auth_data
end
end

# @param exec_conf [K8s::Config::UserExec]
# @return [String]
def self.token_from_exec(exec_conf)
cmd = [exec_conf.command]
cmd += exec_conf.args if exec_conf.args
orig_env = ENV.to_h
if envs = exec_conf.env
envs.each do |env|
ENV[env['name']] = env['value']
end
end
auth_json = `#{cmd.join(' ')}`.strip
ENV.replace(orig_env)

JSON.parse(auth_json).dig('status', 'token')
end

# In-cluster config within a kube pod, using the kubernetes service envs and serviceaccount secrets
#
# @param options [Hash] see #new
Expand Down
7 changes: 7 additions & 0 deletions spec/fixtures/config/kubeconfig_user_exec_data.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"apiVersion": "client.authentication.k8s.io/v1beta1",
"kind": "ExecCredential",
"status": {
"token": "my-bearer-token"
}
}
55 changes: 55 additions & 0 deletions spec/k8s/transport_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -213,7 +213,62 @@
end
end

context 'for a kubeconfig using exec' do
let(:config) { K8s::Config.new(
clusters: [
{
name: 'kubernetes',
cluster: {
server: 'http://localhost:8080',
certificate_authority: 'ca.pem',

}
}
],
users: [
{
name: 'test',
user: {
exec: {
apiVersion: 'client.authentication.k8s.io/v1beta1',
command: 'cat',
env: [
{ 'name' => 'CUSTOM_ENV', 'value' => '123' }
],
args: [
"#{fixture_path}/config/kubeconfig_user_exec_data.json"
]
}
}
}
],

contexts: [
{
name: 'test',
context: {
cluster: 'kubernetes',
user: 'test'
}
}
],
current_context: 'test'
) }

subject { described_class.config(config) }

describe '#request_options' do
it "includes the Authorization token" do
expect(subject.request_options(method: 'GET', path: '/')).to eq({
method: 'GET',
path: '/',
headers: {
'Authorization' => 'Bearer my-bearer-token',
},
})
end
end
end

describe '#self.in_cluster_config' do
context "with envs set" do
Expand Down

0 comments on commit 14d4999

Please sign in to comment.