Skip to content

Instantly share code, notes, and snippets.

@sheerun
Last active April 10, 2022 15:39
Show Gist options
  • Star 42 You must be signed in to star a gist
  • Fork 22 You must be signed in to fork a gist
  • Save sheerun/ccdeff92ea1668f3c75f to your computer and use it in GitHub Desktop.
Save sheerun/ccdeff92ea1668f3c75f to your computer and use it in GitHub Desktop.
Docker TLS certificate generator
# Generates necessary certificates to ~/.docker
#
# Usage:
# bundle install
# ruby certgen.rb <domain>
require 'certificate_authority'
require 'fileutils'
if ARGV.empty?
puts "Usage: ruby certgen.rb <domain>"
exit 1
end
$domain = ARGV[0]
$certs_path = File.join(ENV['HOME'], '.docker')
def certificate_authority
cert_path = File.join($certs_path, 'ca', 'cert.pem')
ca_path = File.join($certs_path, 'ca', 'key.pem')
key_material = if File.exist?(ca_path)
key = OpenSSL::PKey::RSA.new(File.read(ca_path))
mem_key = CertificateAuthority::MemoryKeyMaterial.new
mem_key.public_key = key.public_key
mem_key.private_key = key
mem_key
else
mem_key = CertificateAuthority::MemoryKeyMaterial.new
mem_key.generate_key
mem_key
end
if File.exist?(cert_path)
raw_cert = File.read(cert_path)
openssl = OpenSSL::X509::Certificate.new(raw_cert)
cert = CertificateAuthority::Certificate.from_openssl(openssl)
cert.key_material = key_material
cert
else
root = CertificateAuthority::Certificate.new
root.subject.common_name = $domain
root.serial_number.number = 1
root.signing_entity = true
root.key_material = key_material
ca_profile = {
"extensions" => {
"keyUsage" => {
"usage" => [ "critical", "keyCertSign" ]
}
}
}
root.sign!(ca_profile)
root
end
end
def server_certificate(root)
server = CertificateAuthority::Certificate.new
server.subject.common_name = $domain
server.serial_number.number = rand(3..100000)
server.parent = root
server.key_material.generate_key
server.sign!
server
end
def client_certificate(root)
client = CertificateAuthority::Certificate.new
client.subject.common_name = $domain
client.serial_number.number = 2
client.parent = root
client.key_material.generate_key
signing_profile = {
"extensions" => {
"extendedKeyUsage" => {
"usage" => [ "clientAuth" ]
}
}
}
client.sign!(signing_profile)
client
end
root = certificate_authority
server = server_certificate(root)
client = client_certificate(root)
[
# You can reuse this file to generate more certs
['ca/key.pem', root.key_material.private_key],
['ca/cert.pem', root.to_pem],
# Those are default filenames expected by Docker
['ca.pem', root.to_pem],
['key.pem', client.key_material.private_key],
['cert.pem', client.to_pem],
# Those files are supposed to be uploaded to server
["#{$domain}/ca.pem", root.to_pem],
["#{$domain}/key.pem", server.key_material.private_key],
["#{$domain}/cert.pem", server.to_pem]
].each do |name, contents|
path = File.join($certs_path, name)
FileUtils.mkdir_p(File.dirname(path))
File.write(path, contents)
File.chmod(0600, path)
end
puts "CA certificates are in #{$certs_path}/ca"
puts "Client certificates are in #{$certs_path}"
puts "Server certificates are in #{$certs_path}/#{$domain}"
@mozinator
Copy link

mozinator commented Oct 20, 2016

its missing the subjectAltName which makes docker-compose complaint about urllib3

at server_certificate add this
and have $ip point to the ip of your server

signing_profile = {
"extensions" => {
"subjectAltName" => {"uris" => ["https://#{$domain}:2376"], "https://#{$ip}:2376"],
"ips" => ["#{$ip}","127.0.0.1"]
}
}
}

@icbd
Copy link

icbd commented Apr 12, 2018

请教一下, 在客户端连接的时候, 要如何设置才能使用双向TLS验证呢?

require 'net/https'
require 'uri'
require 'openssl'

uri = URI.parse('https://test.com:2375/containers/json')
http = Net::HTTP.new(uri.host, uri.port)
http.use_ssl = true
http.cert = OpenSSL::X509::Certificate.new(File.read("/Users/cbd/.docker/cert.pem"))
http.key = OpenSSL::PKey::RSA.new((File.read("/Users/cbd/.docker/key.pem")))
http.ca_file = "/Users/cbd/.docker/"

http.verify_mode = OpenSSL::SSL::VERIFY_PEER

http.start {
  http.request_get(uri.path) { |res|
    print res.body
  }
}

用 VERIFY_NONE 是可以连通的, 也就是服务器验证客户端证书成功了. 但使用 VERIFY_PEER 的时候就报错.
是哪个环节出问题了呢?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment