.k8s/bin/secret
#!/usr/bin/env ruby
#
# secret
# Usage:
# kubernetes_deploy/bin/secret -e [dev, staging, etc] options.
#
# Notes:
# - Contexts are those available in your kubernetes config.
# if the current-context is the one you wish to query then you
# do not needed to specify it.
# - For a list of secrets to query `kubectl get secrets`
#
# Examples:
# most basic example if current-context is the one you want
# `kubernetes_deploy/bin/secret -e dev`
#
# output base64 decoded cccd-secrets oject to STDOUT
# `kubernetes_deploy/bin/secret -c live -e dev -d`
#
# write base64 decoded cccd-secrets oject to a .gitignored temp file
# `kubernetes_deploy/bin/secret -c live -e dev -dw`
#
# query the s3 bucket secrets
# `kubernetes_deploy/bin/secret -c live -e dev -d -s cccd-s3-bucket`
#
require 'optparse'
require 'ostruct'
require 'yaml'
require 'base64'
# rubocop:disable Metrics/MethodLength, Metrics/BlockLength, Metrics/AbcSize
class SecretOptParser
ENVIRONMENTS = %w[dev staging api-sandbox production].freeze
def self.parse(args)
options = OpenStruct.new
options.context = `kubectl config current-context`.chomp
options.decode = false
options.write = false
options.secret = 'cccd-secrets'
secret_opt_parser = OptionParser.new do |opts|
opts.banner = "Usage: #{__FILE__} [options]"
opts.separator ''
opts.separator 'Specific options:'
opts.on('-e',
'--env ENVIRONMENT',
'Required: the Environment for executing your script',
" (#{ENVIRONMENTS.join(', ')})") do |env|
options.environment = env
end
opts.on('-c',
'--context [CONTEXT]',
'Optional: Set context, defaults to k8s current-context') do |context|
options.context = context
end
opts.on('-s',
'--secret [SECRETS_OBJECT]',
'Optional: the secret object from which to retrieve key-value pairs (default cccd-secrets)') do |secret|
options.secret = secret
end
opts.on('-d',
'--[no-]decode',
'Optional: Decode base64, defaults to false') do |decode|
options.decode = decode
end
opts.on(
'-w', '--[no-]write',
<<~OPT
Optional: write output to file as yaml,
Always writes to temp_<options.environment>_secrets.yaml
OPT
) do |write|
options.write = write
end
opts.on_tail('-h', '--help', 'Show this message') do
puts opts
exit
end
end
secret_opt_parser.parse!(args)
options
end
end
# rubocop:enable Metrics/MethodLength, Metrics/BlockLength, Metrics/AbcSize
def options
@options ||= SecretOptParser.parse(ARGV)
end
def grep_excludes
@grep_excludes ||= 'annotations|last-applied-configuration|creationTimestamp|resourceVersion|selfLink|uid'
end
def write_file(secrets)
file = File.join('.k8s', options.context, options.environment, "temp_#{options.environment}_secrets.yaml")
File.write(file, secrets)
puts "secrets written to #{file}"
end
def check_requirements
return unless options.environment.nil? || options.context.nil?
puts 'context and environment required!'
exit
end
def secrets
return @secrets unless @secrets.nil?
puts "Running command: #{secret_cmd}"
@secrets = YAML.safe_load(`#{secret_cmd}`.chomp)
@secrets['data'].transform_values! { |v| Base64.decode64(v) unless v.nil? } if options.decode
@secrets
end
def secret_cmd
@secret_cmd ||= "kubectl --context #{options.context} -n cccd-#{options.environment} get secret #{options.secret} -o yaml | grep -vE '#{grep_excludes}'"
end
# entrypoint
check_requirements
options.write ? write_file(secrets.to_yaml) : puts(secrets.to_yaml)