Remove custom ssl code and add TLS support in Ingress rules
This commit is contained in:
parent
5feb452ce4
commit
6cb0e41737
11 changed files with 190 additions and 226 deletions
55
controllers/nginx-third-party/controller.go
vendored
55
controllers/nginx-third-party/controller.go
vendored
|
@ -243,8 +243,6 @@ func (lbc *loadBalancerController) sync() {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (lbc *loadBalancerController) getUpstreamServers(data []interface{}) ([]nginx.Upstream, []nginx.Server) {
|
func (lbc *loadBalancerController) getUpstreamServers(data []interface{}) ([]nginx.Upstream, []nginx.Server) {
|
||||||
pems := make(map[string]string)
|
|
||||||
|
|
||||||
upstreams := make(map[string]nginx.Upstream)
|
upstreams := make(map[string]nginx.Upstream)
|
||||||
servers := make(map[string]nginx.Server)
|
servers := make(map[string]nginx.Server)
|
||||||
|
|
||||||
|
@ -297,6 +295,8 @@ func (lbc *loadBalancerController) getUpstreamServers(data []interface{}) ([]ngi
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pems := lbc.getPemsFromIngress(data)
|
||||||
|
|
||||||
for _, rule := range ing.Spec.Rules {
|
for _, rule := range ing.Spec.Rules {
|
||||||
var server nginx.Server
|
var server nginx.Server
|
||||||
if existent, ok := servers[rule.Host]; ok {
|
if existent, ok := servers[rule.Host]; ok {
|
||||||
|
@ -317,6 +317,18 @@ func (lbc *loadBalancerController) getUpstreamServers(data []interface{}) ([]ngi
|
||||||
loc := nginx.Location{Path: path.Path}
|
loc := nginx.Location{Path: path.Path}
|
||||||
upsName := ing.GetNamespace() + "-" + path.Backend.ServiceName
|
upsName := ing.GetNamespace() + "-" + path.Backend.ServiceName
|
||||||
|
|
||||||
|
svcKey := ing.GetNamespace() + "/" + path.Backend.ServiceName
|
||||||
|
_, svcExists, err := lbc.svcLister.Store.GetByKey(svcKey)
|
||||||
|
if err != nil {
|
||||||
|
glog.Infof("error getting service %v from the cache: %v", svcKey, err)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
if !svcExists {
|
||||||
|
glog.Warningf("service %v does no exists. skipping Ingress rule", svcKey)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
for _, ups := range upstreams {
|
for _, ups := range upstreams {
|
||||||
if upsName == ups.Name {
|
if upsName == ups.Name {
|
||||||
loc.Upstream = ups
|
loc.Upstream = ups
|
||||||
|
@ -350,6 +362,41 @@ func (lbc *loadBalancerController) getUpstreamServers(data []interface{}) ([]ngi
|
||||||
return aUpstreams, aServers
|
return aUpstreams, aServers
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (lbc *loadBalancerController) getPemsFromIngress(data []interface{}) map[string]string {
|
||||||
|
pems := make(map[string]string)
|
||||||
|
|
||||||
|
for _, ingIf := range data {
|
||||||
|
ing := ingIf.(*extensions.Ingress)
|
||||||
|
|
||||||
|
for _, tls := range ing.Spec.TLS {
|
||||||
|
secretName := tls.SecretName
|
||||||
|
secret, err := lbc.client.Secrets(ing.Namespace).Get(secretName)
|
||||||
|
if err != nil {
|
||||||
|
glog.Warningf("Error retriveing secret %v for ing %v: %v", secretName, ing.Name, err)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
cert, ok := secret.Data[api.TLSCertKey]
|
||||||
|
if !ok {
|
||||||
|
glog.Warningf("Secret %v has no private key", secretName)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
key, ok := secret.Data[api.TLSPrivateKeyKey]
|
||||||
|
if !ok {
|
||||||
|
glog.Warningf("Secret %v has no cert", secretName)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
pemFileName := lbc.nginx.AddOrUpdateCertAndKey(secretName, string(cert), string(key))
|
||||||
|
|
||||||
|
for _, host := range tls.Hosts {
|
||||||
|
pems[host] = pemFileName
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return pems
|
||||||
|
}
|
||||||
|
|
||||||
// getEndpoints returns a list of <endpoint ip>:<port> for a given service/target port combination.
|
// getEndpoints returns a list of <endpoint ip>:<port> for a given service/target port combination.
|
||||||
func (lbc *loadBalancerController) getEndpoints(s *api.Service, servicePort intstr.IntOrString) []nginx.UpstreamServer {
|
func (lbc *loadBalancerController) getEndpoints(s *api.Service, servicePort intstr.IntOrString) []nginx.UpstreamServer {
|
||||||
ep, err := lbc.endpLister.GetServiceEndpoints(s)
|
ep, err := lbc.endpLister.GetServiceEndpoints(s)
|
||||||
|
@ -415,9 +462,7 @@ func (lbc *loadBalancerController) Run() {
|
||||||
go lbc.svcController.Run(lbc.stopCh)
|
go lbc.svcController.Run(lbc.stopCh)
|
||||||
|
|
||||||
// periodic check for changes in configuration
|
// periodic check for changes in configuration
|
||||||
go wait.Until(lbc.sync, 5*time.Second, wait.NeverStop)
|
go wait.Until(lbc.sync, 10*time.Second, wait.NeverStop)
|
||||||
|
|
||||||
time.Sleep(5 * time.Second)
|
|
||||||
|
|
||||||
<-lbc.stopCh
|
<-lbc.stopCh
|
||||||
glog.Infof("shutting down NGINX loadbalancer controller")
|
glog.Infof("shutting down NGINX loadbalancer controller")
|
||||||
|
|
|
@ -5,7 +5,10 @@ function openURL(status, page)
|
||||||
|
|
||||||
local res, err = httpc:request_uri(page, {
|
local res, err = httpc:request_uri(page, {
|
||||||
path = "/",
|
path = "/",
|
||||||
method = "GET"
|
method = "GET",
|
||||||
|
headers = {
|
||||||
|
["Content-Type"] = ngx.var.httpReturnType or "text/html",
|
||||||
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
if not res then
|
if not res then
|
||||||
|
|
|
@ -56,6 +56,7 @@ server {
|
||||||
content_by_lua '
|
content_by_lua '
|
||||||
|
|
||||||
-- For simple singleshot requests, use the URI interface.
|
-- For simple singleshot requests, use the URI interface.
|
||||||
|
local http = require "resty.http"
|
||||||
local httpc = http.new()
|
local httpc = http.new()
|
||||||
local res, err = httpc:request_uri("http://example.com/helloworld", {
|
local res, err = httpc:request_uri("http://example.com/helloworld", {
|
||||||
method = "POST",
|
method = "POST",
|
||||||
|
|
|
@ -67,7 +67,7 @@ end
|
||||||
|
|
||||||
|
|
||||||
local _M = {
|
local _M = {
|
||||||
_VERSION = '0.06',
|
_VERSION = '0.07',
|
||||||
}
|
}
|
||||||
_M._USER_AGENT = "lua-resty-http/" .. _M._VERSION .. " (Lua) ngx_lua/" .. ngx.config.ngx_lua_version
|
_M._USER_AGENT = "lua-resty-http/" .. _M._VERSION .. " (Lua) ngx_lua/" .. ngx.config.ngx_lua_version
|
||||||
|
|
||||||
|
@ -196,7 +196,7 @@ function _M.parse_uri(self, uri)
|
||||||
m[3] = 80
|
m[3] = 80
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
if not m[4] then m[4] = "/" end
|
if not m[4] or "" == m[4] then m[4] = "/" end
|
||||||
return m, nil
|
return m, nil
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -805,7 +805,11 @@ function _M.proxy_response(self, response, chunksize)
|
||||||
end
|
end
|
||||||
|
|
||||||
if chunk then
|
if chunk then
|
||||||
ngx.print(chunk)
|
local res, err = ngx.print(chunk)
|
||||||
|
if not res then
|
||||||
|
ngx_log(ngx_ERR, err)
|
||||||
|
break
|
||||||
|
end
|
||||||
end
|
end
|
||||||
until not chunk
|
until not chunk
|
||||||
end
|
end
|
||||||
|
|
|
@ -1,12 +1,12 @@
|
||||||
package = "lua-resty-http"
|
package = "lua-resty-http"
|
||||||
version = "0.06-0"
|
version = "0.07-0"
|
||||||
source = {
|
source = {
|
||||||
url = "git://github.com/pintsized/lua-resty-http",
|
url = "git://github.com/pintsized/lua-resty-http",
|
||||||
tag = "v0.06"
|
tag = "v0.07"
|
||||||
}
|
}
|
||||||
description = {
|
description = {
|
||||||
summary = "Lua HTTP client cosocket driver for OpenResty / ngx_lua.",
|
summary = "Lua HTTP client cosocket driver for OpenResty / ngx_lua.",
|
||||||
detailed = [[
|
detailed = [[
|
||||||
Features an HTTP 1.0 and 1.1 streaming interface to reading
|
Features an HTTP 1.0 and 1.1 streaming interface to reading
|
||||||
bodies using coroutines, for predictable memory usage in Lua
|
bodies using coroutines, for predictable memory usage in Lua
|
||||||
land. Alternative simple interface for singleshot requests
|
land. Alternative simple interface for singleshot requests
|
||||||
|
@ -17,17 +17,17 @@ description = {
|
||||||
Recommended by the OpenResty maintainer as a long-term
|
Recommended by the OpenResty maintainer as a long-term
|
||||||
replacement for internal requests through ngx.location.capture.
|
replacement for internal requests through ngx.location.capture.
|
||||||
]],
|
]],
|
||||||
homepage = "https://github.com/pintsized/lua-resty-http",
|
homepage = "https://github.com/pintsized/lua-resty-http",
|
||||||
license = "2-clause BSD",
|
license = "2-clause BSD",
|
||||||
maintainer = "James Hurst <james@pintsized.co.uk>"
|
maintainer = "James Hurst <james@pintsized.co.uk>"
|
||||||
}
|
}
|
||||||
dependencies = {
|
dependencies = {
|
||||||
"lua >= 5.1",
|
"lua >= 5.1"
|
||||||
}
|
}
|
||||||
build = {
|
build = {
|
||||||
type = "builtin",
|
type = "builtin",
|
||||||
modules = {
|
modules = {
|
||||||
["resty.http"] = "lib/resty/http.lua",
|
["resty.http"] = "lib/resty/http.lua",
|
||||||
["resty.http_headers"] = "lib/resty/http_headers.lua"
|
["resty.http_headers"] = "lib/resty/http_headers.lua"
|
||||||
}
|
}
|
||||||
}
|
}
|
52
controllers/nginx-third-party/lua/vendor/lua-resty-http/t/13-default-path.t
vendored
Normal file
52
controllers/nginx-third-party/lua/vendor/lua-resty-http/t/13-default-path.t
vendored
Normal file
|
@ -0,0 +1,52 @@
|
||||||
|
# vim:set ft= ts=4 sw=4 et:
|
||||||
|
|
||||||
|
use Test::Nginx::Socket;
|
||||||
|
use Cwd qw(cwd);
|
||||||
|
|
||||||
|
plan tests => repeat_each() * (blocks() * 3);
|
||||||
|
|
||||||
|
my $pwd = cwd();
|
||||||
|
|
||||||
|
our $HttpConfig = qq{
|
||||||
|
lua_package_path "$pwd/lib/?.lua;;";
|
||||||
|
error_log logs/error.log debug;
|
||||||
|
};
|
||||||
|
|
||||||
|
$ENV{TEST_NGINX_RESOLVER} = '8.8.8.8';
|
||||||
|
|
||||||
|
no_long_string();
|
||||||
|
#no_diff();
|
||||||
|
|
||||||
|
run_tests();
|
||||||
|
|
||||||
|
__DATA__
|
||||||
|
=== TEST 1: request_uri (check the default path)
|
||||||
|
--- http_config eval: $::HttpConfig
|
||||||
|
--- config
|
||||||
|
location /lua {
|
||||||
|
content_by_lua '
|
||||||
|
local http = require "resty.http"
|
||||||
|
local httpc = http.new()
|
||||||
|
|
||||||
|
local res, err = httpc:request_uri("http://127.0.0.1:"..ngx.var.server_port)
|
||||||
|
|
||||||
|
if res and 200 == res.status then
|
||||||
|
ngx.say("OK")
|
||||||
|
else
|
||||||
|
ngx.say("FAIL")
|
||||||
|
end
|
||||||
|
';
|
||||||
|
}
|
||||||
|
|
||||||
|
location =/ {
|
||||||
|
content_by_lua '
|
||||||
|
ngx.print("OK")
|
||||||
|
';
|
||||||
|
}
|
||||||
|
--- request
|
||||||
|
GET /lua
|
||||||
|
--- response_body
|
||||||
|
OK
|
||||||
|
--- no_error_log
|
||||||
|
[error]
|
||||||
|
|
38
controllers/nginx-third-party/nginx.tmpl
vendored
38
controllers/nginx-third-party/nginx.tmpl
vendored
|
@ -1,4 +1,4 @@
|
||||||
{{ $cfg := .cfg }}{{ $sslCertificates := .sslCertificates }}{{ $defErrorSvc := .defErrorSvc }}{{ $defBackend := .defBackend }}
|
{{ $cfg := .cfg }}{{ $defErrorSvc := .defErrorSvc }}{{ $defBackend := .defBackend }}
|
||||||
daemon off;
|
daemon off;
|
||||||
|
|
||||||
worker_processes {{ $cfg.WorkerProcesses }};
|
worker_processes {{ $cfg.WorkerProcesses }};
|
||||||
|
@ -17,13 +17,13 @@ http {
|
||||||
lua_package_path '.?.lua;./etc/nginx/lua/?.lua;/etc/nginx/lua/vendor/lua-resty-http/lib/?.lua;';
|
lua_package_path '.?.lua;./etc/nginx/lua/?.lua;/etc/nginx/lua/vendor/lua-resty-http/lib/?.lua;';
|
||||||
|
|
||||||
init_by_lua_block {
|
init_by_lua_block {
|
||||||
|
def_backend = "http://{{ $defBackend.ServiceName }}.{{ $defBackend.Namespace }}.svc.cluster.local:{{ $defBackend.ServicePort }}"
|
||||||
|
|
||||||
{{ if $defErrorSvc }}{{/* only if exists a custom error service */}}
|
{{ if $defErrorSvc }}{{/* only if exists a custom error service */}}
|
||||||
dev_error_url = "http://{{ $defErrorSvc.ServiceName }}.{{ $defErrorSvc.Namespace }}.svc.cluster.local:{{ $defErrorSvc.ServicePort }}"
|
dev_error_url = "http://{{ $defErrorSvc.ServiceName }}.{{ $defErrorSvc.Namespace }}.svc.cluster.local:{{ $defErrorSvc.ServicePort }}"
|
||||||
{{ else }}
|
{{ else }}
|
||||||
dev_error_url = nil
|
dev_error_url = def_backend
|
||||||
{{ end }}
|
{{ end }}
|
||||||
local options = {}
|
|
||||||
def_backend = "http://{{ $defBackend.ServiceName }}.{{ $defBackend.Namespace }}.svc.cluster.local:{{ $defBackend.ServicePort }}"
|
|
||||||
|
|
||||||
require("error_page")
|
require("error_page")
|
||||||
}
|
}
|
||||||
|
@ -178,25 +178,6 @@ http {
|
||||||
{{ if $defErrorSvc }}{{ template "CUSTOM_ERRORS" (dict "cfg" $cfg "defErrorSvc" $defErrorSvc) }}{{ end }}
|
{{ if $defErrorSvc }}{{ template "CUSTOM_ERRORS" (dict "cfg" $cfg "defErrorSvc" $defErrorSvc) }}{{ end }}
|
||||||
}
|
}
|
||||||
|
|
||||||
{{ if ge (len .sslCertificates) 1 }}
|
|
||||||
# SSL
|
|
||||||
# TODO: support more than one certificate
|
|
||||||
server {
|
|
||||||
listen 443 ssl http2 default_server;
|
|
||||||
{{ range $sslCert := .sslCertificates }}{{ if $sslCert.Default }}
|
|
||||||
# default certificate in case no match
|
|
||||||
ssl_certificate "{{ $sslCert.Cert }}";
|
|
||||||
ssl_certificate_key "{{ $sslCert.Key }}";
|
|
||||||
{{ end }}{{ end }}
|
|
||||||
|
|
||||||
location / {
|
|
||||||
proxy_pass http://{{ $defBackend.ServiceName }}.{{ $defBackend.Namespace }}.svc.cluster.local:{{ $defBackend.ServicePort }};
|
|
||||||
}
|
|
||||||
|
|
||||||
{{ if $defErrorSvc }}{{ template "CUSTOM_ERRORS" (dict "cfg" $cfg "defErrorSvc" $defErrorSvc) }}{{ end }}
|
|
||||||
}
|
|
||||||
{{ end }}
|
|
||||||
|
|
||||||
{{range $name, $upstream := .upstreams}}
|
{{range $name, $upstream := .upstreams}}
|
||||||
upstream {{$upstream.Name}} {
|
upstream {{$upstream.Name}} {
|
||||||
least_conn;
|
least_conn;
|
||||||
|
@ -256,6 +237,17 @@ http {
|
||||||
}
|
}
|
||||||
{{ if $defErrorSvc }}{{ template "CUSTOM_ERRORS" (dict "cfg" $cfg "defErrorSvc" $defErrorSvc) }}{{ end }}
|
{{ if $defErrorSvc }}{{ template "CUSTOM_ERRORS" (dict "cfg" $cfg "defErrorSvc" $defErrorSvc) }}{{ end }}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# default server for services without endpoints
|
||||||
|
server {
|
||||||
|
listen 8081;
|
||||||
|
|
||||||
|
location / {
|
||||||
|
content_by_lua_block {
|
||||||
|
openURL(503, dev_error_url)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
# TCP services
|
# TCP services
|
||||||
|
|
34
controllers/nginx-third-party/nginx/main.go
vendored
34
controllers/nginx-third-party/nginx/main.go
vendored
|
@ -17,6 +17,7 @@ limitations under the License.
|
||||||
package nginx
|
package nginx
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"os"
|
||||||
"runtime"
|
"runtime"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
|
@ -27,7 +28,6 @@ import (
|
||||||
|
|
||||||
"k8s.io/contrib/ingress/controllers/nginx-third-party/ssl"
|
"k8s.io/contrib/ingress/controllers/nginx-third-party/ssl"
|
||||||
|
|
||||||
"k8s.io/kubernetes/pkg/client/record"
|
|
||||||
client "k8s.io/kubernetes/pkg/client/unversioned"
|
client "k8s.io/kubernetes/pkg/client/unversioned"
|
||||||
k8sruntime "k8s.io/kubernetes/pkg/runtime"
|
k8sruntime "k8s.io/kubernetes/pkg/runtime"
|
||||||
)
|
)
|
||||||
|
@ -220,9 +220,9 @@ type NginxManager struct {
|
||||||
// path to the configuration file to be used by nginx
|
// path to the configuration file to be used by nginx
|
||||||
ConfigFile string
|
ConfigFile string
|
||||||
|
|
||||||
sslCertificates []ssl.Certificate
|
sslDHParam string
|
||||||
sslDHParam string
|
|
||||||
servicesL4 []Service
|
servicesL4 []Service
|
||||||
|
|
||||||
client *client.Client
|
client *client.Client
|
||||||
// template loaded ready to be used to generate the nginx configuration file
|
// template loaded ready to be used to generate the nginx configuration file
|
||||||
|
@ -231,8 +231,6 @@ type NginxManager struct {
|
||||||
// obj runtime object to be used in events
|
// obj runtime object to be used in events
|
||||||
obj k8sruntime.Object
|
obj k8sruntime.Object
|
||||||
|
|
||||||
recorder record.EventRecorder
|
|
||||||
|
|
||||||
reloadLock *sync.Mutex
|
reloadLock *sync.Mutex
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -276,17 +274,25 @@ func newDefaultNginxCfg() *nginxConfiguration {
|
||||||
// NewManager ...
|
// NewManager ...
|
||||||
func NewManager(kubeClient *client.Client, defaultSvc, customErrorSvc Service) *NginxManager {
|
func NewManager(kubeClient *client.Client, defaultSvc, customErrorSvc Service) *NginxManager {
|
||||||
ngx := &NginxManager{
|
ngx := &NginxManager{
|
||||||
ConfigFile: "/etc/nginx/nginx.conf",
|
ConfigFile: "/etc/nginx/nginx.conf",
|
||||||
defBackend: defaultSvc,
|
defBackend: defaultSvc,
|
||||||
defCfg: newDefaultNginxCfg(),
|
defCfg: newDefaultNginxCfg(),
|
||||||
defError: customErrorSvc,
|
defError: customErrorSvc,
|
||||||
defResolver: strings.Join(getDnsServers(), " "),
|
defResolver: strings.Join(getDnsServers(), " "),
|
||||||
reloadLock: &sync.Mutex{},
|
reloadLock: &sync.Mutex{},
|
||||||
sslDHParam: ssl.SearchDHParamFile(sslDirectory),
|
|
||||||
sslCertificates: ssl.CreateSSLCerts(sslDirectory),
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ngx.createCertsDir(sslDirectory)
|
||||||
|
|
||||||
|
ngx.sslDHParam = ssl.SearchDHParamFile(sslDirectory)
|
||||||
|
|
||||||
ngx.loadTemplate()
|
ngx.loadTemplate()
|
||||||
|
|
||||||
return ngx
|
return ngx
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (nginx *NginxManager) createCertsDir(base string) {
|
||||||
|
if err := os.Mkdir(base, os.ModeDir); err != nil {
|
||||||
|
glog.Fatalf("Couldn't create directory %v: %v", base, err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
34
controllers/nginx-third-party/nginx/nginx.go
vendored
34
controllers/nginx-third-party/nginx/nginx.go
vendored
|
@ -16,13 +16,11 @@ limitations under the License.
|
||||||
|
|
||||||
package nginx
|
package nginx
|
||||||
|
|
||||||
// NGINXController Updates NGINX configuration, starts and reloads NGINX
|
import (
|
||||||
type NGINXController struct {
|
"os"
|
||||||
resolver string
|
|
||||||
nginxConfdPath string
|
"github.com/golang/glog"
|
||||||
nginxCertsPath string
|
)
|
||||||
local bool
|
|
||||||
}
|
|
||||||
|
|
||||||
// IngressNGINXConfig describes an NGINX configuration
|
// IngressNGINXConfig describes an NGINX configuration
|
||||||
type IngressNGINXConfig struct {
|
type IngressNGINXConfig struct {
|
||||||
|
@ -113,3 +111,25 @@ func NewUpstream(name string) Upstream {
|
||||||
Backends: []UpstreamServer{},
|
Backends: []UpstreamServer{},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// AddOrUpdateCertAndKey creates a .pem file wth the cert and the key with the specified name
|
||||||
|
func (nginx *NginxManager) AddOrUpdateCertAndKey(name string, cert string, key string) string {
|
||||||
|
pemFileName := sslDirectory + "/" + name + ".pem"
|
||||||
|
|
||||||
|
pem, err := os.Create(pemFileName)
|
||||||
|
if err != nil {
|
||||||
|
glog.Fatalf("Couldn't create pem file %v: %v", pemFileName, err)
|
||||||
|
}
|
||||||
|
defer pem.Close()
|
||||||
|
|
||||||
|
_, err = pem.WriteString(string(key))
|
||||||
|
if err != nil {
|
||||||
|
glog.Fatalf("Couldn't write to pem file %v: %v", pemFileName, err)
|
||||||
|
}
|
||||||
|
_, err = pem.WriteString(string(cert))
|
||||||
|
if err != nil {
|
||||||
|
glog.Fatalf("Couldn't write to pem file %v: %v", pemFileName, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return pemFileName
|
||||||
|
}
|
||||||
|
|
|
@ -25,12 +25,9 @@ import (
|
||||||
|
|
||||||
"github.com/fatih/structs"
|
"github.com/fatih/structs"
|
||||||
"github.com/golang/glog"
|
"github.com/golang/glog"
|
||||||
|
|
||||||
"k8s.io/contrib/ingress/controllers/nginx-third-party/ssl"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
var funcMap = template.FuncMap{
|
var funcMap = template.FuncMap{
|
||||||
"getSSLHost": ssl.GetSSLHost,
|
|
||||||
"empty": func(input interface{}) bool {
|
"empty": func(input interface{}) bool {
|
||||||
check, ok := input.(string)
|
check, ok := input.(string)
|
||||||
if ok {
|
if ok {
|
||||||
|
@ -66,7 +63,6 @@ func (ngx *NginxManager) writeCfg(cfg *nginxConfiguration, upstreams []Upstream,
|
||||||
curNginxCfg := merge(toMap, fromMap)
|
curNginxCfg := merge(toMap, fromMap)
|
||||||
|
|
||||||
conf := make(map[string]interface{})
|
conf := make(map[string]interface{})
|
||||||
conf["sslCertificates"] = ngx.sslCertificates
|
|
||||||
conf["upstreams"] = upstreams
|
conf["upstreams"] = upstreams
|
||||||
conf["servers"] = servers
|
conf["servers"] = servers
|
||||||
conf["tcpServices"] = servicesL4
|
conf["tcpServices"] = servicesL4
|
||||||
|
|
155
controllers/nginx-third-party/ssl/main.go
vendored
155
controllers/nginx-third-party/ssl/main.go
vendored
|
@ -17,139 +17,13 @@ limitations under the License.
|
||||||
package ssl
|
package ssl
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"crypto/tls"
|
|
||||||
"crypto/x509"
|
|
||||||
"encoding/pem"
|
|
||||||
"fmt"
|
"fmt"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
|
||||||
"regexp"
|
|
||||||
"strings"
|
|
||||||
|
|
||||||
"github.com/golang/glog"
|
"github.com/golang/glog"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Certificate contains the cert, key and the list of valid hostnames
|
|
||||||
type Certificate struct {
|
|
||||||
Cert string
|
|
||||||
Key string
|
|
||||||
Cname []string
|
|
||||||
Valid bool
|
|
||||||
Default bool
|
|
||||||
}
|
|
||||||
|
|
||||||
// CreateSSLCerts reads the content of the /etc/nginx-ssl directory and
|
|
||||||
// verifies the cert and key extracting the common names for this pair
|
|
||||||
func CreateSSLCerts(baseDir string) []Certificate {
|
|
||||||
sslCerts := []Certificate{}
|
|
||||||
|
|
||||||
glog.Infof("inspecting directory %v for SSL certificates\n", baseDir)
|
|
||||||
files, _ := ioutil.ReadDir(baseDir)
|
|
||||||
for _, file := range files {
|
|
||||||
if !file.IsDir() {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
// the name of the secret could be different than the certificate file
|
|
||||||
cert, key, err := getCert(fmt.Sprintf("%v/%v", baseDir, file.Name()))
|
|
||||||
if err != nil {
|
|
||||||
glog.Errorf("error checking certificate: %v", err)
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
hosts, err := checkSSLCertificate(cert, key)
|
|
||||||
if err == nil {
|
|
||||||
sslCert := Certificate{
|
|
||||||
Cert: cert,
|
|
||||||
Key: key,
|
|
||||||
Cname: hosts,
|
|
||||||
Valid: true,
|
|
||||||
}
|
|
||||||
|
|
||||||
if file.Name() == "default" {
|
|
||||||
sslCert.Default = true
|
|
||||||
}
|
|
||||||
|
|
||||||
sslCerts = append(sslCerts, sslCert)
|
|
||||||
} else {
|
|
||||||
glog.Errorf("error checking certificate: %v", err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(sslCerts) == 1 {
|
|
||||||
sslCerts[0].Default = true
|
|
||||||
}
|
|
||||||
|
|
||||||
glog.Infof("ssl certificates found: %v", sslCerts)
|
|
||||||
|
|
||||||
return sslCerts
|
|
||||||
}
|
|
||||||
|
|
||||||
// checkSSLCertificate check if the certificate and key file are valid
|
|
||||||
// returning the result of the validation and the list of hostnames
|
|
||||||
// contained in the common name/s
|
|
||||||
func checkSSLCertificate(certFile, keyFile string) ([]string, error) {
|
|
||||||
_, err := tls.LoadX509KeyPair(certFile, keyFile)
|
|
||||||
if err != nil {
|
|
||||||
glog.Errorf("Error checking certificate and key file %v/%v: %v", certFile, keyFile, err)
|
|
||||||
return []string{}, err
|
|
||||||
}
|
|
||||||
|
|
||||||
pemCerts, err := ioutil.ReadFile(certFile)
|
|
||||||
if err != nil {
|
|
||||||
return []string{}, err
|
|
||||||
}
|
|
||||||
|
|
||||||
var block *pem.Block
|
|
||||||
block, pemCerts = pem.Decode(pemCerts)
|
|
||||||
|
|
||||||
cert, err := x509.ParseCertificate(block.Bytes)
|
|
||||||
if err != nil {
|
|
||||||
glog.Errorf("Error checking certificate and key file %v/%v: %v", certFile, keyFile, err)
|
|
||||||
return []string{}, err
|
|
||||||
}
|
|
||||||
|
|
||||||
cn := []string{cert.Subject.CommonName}
|
|
||||||
if len(cert.DNSNames) > 0 {
|
|
||||||
cn = append(cn, cert.DNSNames...)
|
|
||||||
}
|
|
||||||
|
|
||||||
glog.Infof("DNS %v %v\n", cn, len(cn))
|
|
||||||
return cn, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func verifyHostname(certFile, host string) bool {
|
|
||||||
pemCerts, err := ioutil.ReadFile(certFile)
|
|
||||||
if err != nil {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
var block *pem.Block
|
|
||||||
block, pemCerts = pem.Decode(pemCerts)
|
|
||||||
|
|
||||||
cert, err := x509.ParseCertificate(block.Bytes)
|
|
||||||
|
|
||||||
err = cert.VerifyHostname(host)
|
|
||||||
if err == nil {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetSSLHost checks if in one of the secrets that contains SSL
|
|
||||||
// certificates could be used for the specified server name
|
|
||||||
func GetSSLHost(serverName string, certs []Certificate) Certificate {
|
|
||||||
for _, sslCert := range certs {
|
|
||||||
if verifyHostname(sslCert.Cert, serverName) {
|
|
||||||
return sslCert
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return Certificate{}
|
|
||||||
}
|
|
||||||
|
|
||||||
// SearchDHParamFile iterates all the secrets mounted inside the /etc/nginx-ssl directory
|
// SearchDHParamFile iterates all the secrets mounted inside the /etc/nginx-ssl directory
|
||||||
// in order to find a file with the name dhparam.pem. If such file exists it will
|
// in order to find a file with the name dhparam.pem. If such file exists it will
|
||||||
// returns the path. If not it just returns an empty string
|
// returns the path. If not it just returns an empty string
|
||||||
|
@ -170,32 +44,3 @@ func SearchDHParamFile(baseDir string) string {
|
||||||
glog.Warning("no file dhparam.pem found in secrets")
|
glog.Warning("no file dhparam.pem found in secrets")
|
||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
|
|
||||||
// getCert returns the pair cert-key if exists or an error
|
|
||||||
func getCert(certDir string) (cert string, key string, err error) {
|
|
||||||
// we search for a file with extension crt
|
|
||||||
filepath.Walk(certDir, func(path string, f os.FileInfo, _ error) error {
|
|
||||||
if !f.IsDir() {
|
|
||||||
r, err := regexp.MatchString(".crt", f.Name())
|
|
||||||
if err == nil && r {
|
|
||||||
cert = f.Name()
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
})
|
|
||||||
|
|
||||||
cert = fmt.Sprintf("%v/%v", certDir, cert)
|
|
||||||
if _, err := os.Stat(cert); os.IsNotExist(err) {
|
|
||||||
return "", "", fmt.Errorf("No certificate found in directory %v: %v", certDir, err)
|
|
||||||
}
|
|
||||||
|
|
||||||
key = strings.Replace(cert, ".crt", ".key", 1)
|
|
||||||
|
|
||||||
if _, err := os.Stat(key); os.IsNotExist(err) {
|
|
||||||
return "", "", fmt.Errorf("No certificate key found in directory %v: %v", certDir, err)
|
|
||||||
}
|
|
||||||
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
Loading…
Reference in a new issue