Only support SSL dynamic mode

This commit is contained in:
Manuel Alejandro de Brito Fontes 2019-08-13 17:14:55 -04:00
parent 333d9fd48d
commit 80bd481abb
No known key found for this signature in database
GPG key ID: 786136016A8BA02A
40 changed files with 415 additions and 709 deletions

View file

@ -18,6 +18,7 @@ package controller
import (
"fmt"
"io/ioutil"
"net/http"
"strconv"
"strings"
@ -63,7 +64,7 @@ func (n *NGINXController) Check(_ *http.Request) error {
if err != nil {
return errors.Wrap(err, "unexpected error reading /proc directory")
}
f, err := n.fileSystem.ReadFile(nginx.PID)
f, err := ioutil.ReadFile(nginx.PID)
if err != nil {
return errors.Wrapf(err, "unexpected error reading %v", nginx.PID)
}

View file

@ -26,7 +26,6 @@ import (
"testing"
"k8s.io/apiserver/pkg/server/healthz"
"k8s.io/kubernetes/pkg/util/filesystem"
"k8s.io/ingress-nginx/internal/file"
ngx_config "k8s.io/ingress-nginx/internal/ingress/controller/config"
@ -55,14 +54,10 @@ func TestNginxCheck(t *testing.T) {
defer server.Close()
server.Start()
// mock filesystem
fs := filesystem.DefaultFs{}
n := &NGINXController{
cfg: &Configuration{
ListenPorts: &ngx_config.ListenPorts{},
},
fileSystem: fs,
}
t.Run("no pid or process", func(t *testing.T) {
@ -72,8 +67,8 @@ func TestNginxCheck(t *testing.T) {
})
// create pid file
fs.MkdirAll("/tmp", file.ReadWriteByUser)
pidFile, err := fs.Create(nginx.PID)
os.MkdirAll("/tmp", file.ReadWriteByUser)
pidFile, err := os.Create(nginx.PID)
if err != nil {
t.Fatalf("unexpected error: %v", err)
}

View file

@ -33,8 +33,6 @@ import (
var (
// EnableSSLChainCompletion Autocomplete SSL certificate chains with missing intermediate CA certificates.
EnableSSLChainCompletion = false
// EnableDynamicCertificates Dynamically update SSL certificates instead of reloading NGINX
EnableDynamicCertificates = true
)
const (
@ -605,6 +603,10 @@ type Configuration struct {
// Lua shared dict configuration data / certificate data
LuaSharedDicts map[string]int `json:"lua-shared-dicts"`
// DefaultSSLCertificate holds the default SSL certificate to use in the configuration
// It can be the fake certificate or the one behind the flag --default-ssl-certificate
DefaultSSLCertificate *ingress.SSLCert `json:"-"`
}
// NewDefault returns the default nginx configuration
@ -764,25 +766,24 @@ func (cfg Configuration) BuildLogFormatUpstream() string {
// TemplateConfig contains the nginx configuration to render the file nginx.conf
type TemplateConfig struct {
ProxySetHeaders map[string]string
AddHeaders map[string]string
BacklogSize int
Backends []*ingress.Backend
PassthroughBackends []*ingress.SSLPassthroughBackend
Servers []*ingress.Server
TCPBackends []ingress.L4Service
UDPBackends []ingress.L4Service
HealthzURI string
Cfg Configuration
IsIPV6Enabled bool
IsSSLPassthroughEnabled bool
NginxStatusIpv4Whitelist []string
NginxStatusIpv6Whitelist []string
RedirectServers interface{}
ListenPorts *ListenPorts
PublishService *apiv1.Service
EnableDynamicCertificates bool
EnableMetrics bool
ProxySetHeaders map[string]string
AddHeaders map[string]string
BacklogSize int
Backends []*ingress.Backend
PassthroughBackends []*ingress.SSLPassthroughBackend
Servers []*ingress.Server
TCPBackends []ingress.L4Service
UDPBackends []ingress.L4Service
HealthzURI string
Cfg Configuration
IsIPV6Enabled bool
IsSSLPassthroughEnabled bool
NginxStatusIpv4Whitelist []string
NginxStatusIpv6Whitelist []string
RedirectServers interface{}
ListenPorts *ListenPorts
PublishService *apiv1.Service
EnableMetrics bool
PID string
StatusSocket string

View file

@ -886,19 +886,18 @@ func (n *NGINXController) serviceEndpoints(svcKey, backendPort string) ([]ingres
return upstreams, nil
}
// overridePemFileNameAndPemSHA should only be called when EnableDynamicCertificates
// ideally this function should not exist, the only reason why we use it is that
// we rely on PemFileName in nginx.tmpl to configure SSL directives
// and PemSHA to force reload
func (n *NGINXController) overridePemFileNameAndPemSHA(cert *ingress.SSLCert) {
// TODO(elvinefendi): It is not great but we currently use PemFileName to decide whether SSL needs to be configured
// in nginx configuration or not. The whole thing needs to be refactored, we should rely on a proper
// signal to configure SSL, not PemFileName.
cert.PemFileName = n.cfg.FakeCertificate.PemFileName
func (n *NGINXController) getDefaultSSLCertificate() *ingress.SSLCert {
// read custom default SSL certificate, fall back to generated default certificate
if n.cfg.DefaultSSLCertificate != "" {
certificate, err := n.store.GetLocalSSLCert(n.cfg.DefaultSSLCertificate)
if err == nil {
return certificate
}
// TODO(elvinefendi): This is again another hacky way of avoiding Nginx reload when certificate
// changes in dynamic SSL mode since FakeCertificate never changes.
cert.PemSHA = n.cfg.FakeCertificate.PemSHA
klog.Warningf("Error loading custom default certificate, falling back to generated default:\n%v", err)
}
return n.cfg.FakeCertificate
}
// createServers builds a map of host name to Server structs from a map of
@ -930,25 +929,10 @@ func (n *NGINXController) createServers(data []*ingress.Ingress,
ProxyHTTPVersion: bdef.ProxyHTTPVersion,
}
defaultCertificate := n.cfg.FakeCertificate
// read custom default SSL certificate, fall back to generated default certificate
if n.cfg.DefaultSSLCertificate != "" {
certificate, err := n.store.GetLocalSSLCert(n.cfg.DefaultSSLCertificate)
if err == nil {
defaultCertificate = certificate
if ngx_config.EnableDynamicCertificates {
n.overridePemFileNameAndPemSHA(defaultCertificate)
}
} else {
klog.Warningf("Error loading custom default certificate, falling back to generated default:\n%v", err)
}
}
// initialize default server and root location
servers[defServerName] = &ingress.Server{
Hostname: defServerName,
SSLCert: *defaultCertificate,
SSLCert: n.getDefaultSSLCertificate(),
Locations: []*ingress.Location{
{
Path: rootLocation,
@ -1012,6 +996,7 @@ func (n *NGINXController) createServers(data []*ingress.Ingress,
if host == "" {
host = defServerName
}
if _, ok := servers[host]; ok {
// server already configured
continue
@ -1079,7 +1064,7 @@ func (n *NGINXController) createServers(data []*ingress.Ingress,
}
// only add a certificate if the server does not have one previously configured
if servers[host].SSLCert.PemFileName != "" {
if servers[host].SSLCert != nil {
continue
}
@ -1089,10 +1074,8 @@ func (n *NGINXController) createServers(data []*ingress.Ingress,
}
tlsSecretName := extractTLSSecretName(host, ing, n.store.GetLocalSSLCert)
if tlsSecretName == "" {
klog.V(3).Infof("Host %q is listed in the TLS section but secretName is empty. Using default certificate.", host)
servers[host].SSLCert = *defaultCertificate
continue
}
@ -1100,7 +1083,6 @@ func (n *NGINXController) createServers(data []*ingress.Ingress,
cert, err := n.store.GetLocalSSLCert(secrKey)
if err != nil {
klog.Warningf("Error getting SSL certificate %q: %v. Using default certificate", secrKey, err)
servers[host].SSLCert = *defaultCertificate
continue
}
@ -1115,16 +1097,11 @@ func (n *NGINXController) createServers(data []*ingress.Ingress,
klog.Warningf("SSL certificate %q does not contain a Common Name or Subject Alternative Name for server %q: %v",
secrKey, host, err)
klog.Warningf("Using default certificate")
servers[host].SSLCert = *defaultCertificate
continue
}
}
if ngx_config.EnableDynamicCertificates {
n.overridePemFileNameAndPemSHA(cert)
}
servers[host].SSLCert = *cert
servers[host].SSLCert = cert
if cert.ExpireTime.Before(time.Now().Add(240 * time.Hour)) {
klog.Warningf("SSL certificate for server %q is about to expire (%v)", host, cert.ExpireTime)

View file

@ -37,7 +37,6 @@ import (
"k8s.io/apimachinery/pkg/util/intstr"
"k8s.io/client-go/kubernetes/fake"
"k8s.io/ingress-nginx/internal/file"
"k8s.io/ingress-nginx/internal/ingress"
"k8s.io/ingress-nginx/internal/ingress/annotations"
"k8s.io/ingress-nginx/internal/ingress/annotations/canary"
@ -1109,11 +1108,6 @@ func newNGINXController(t *testing.T) *NGINXController {
t.Fatalf("error creating the configuration map: %v", err)
}
fs, err := file.NewFakeFS()
if err != nil {
t.Fatalf("error: %v", err)
}
storer := store.New(
ns,
fmt.Sprintf("%v/config", ns),
@ -1122,12 +1116,11 @@ func newNGINXController(t *testing.T) *NGINXController {
"",
10*time.Minute,
clientSet,
fs,
channels.NewRingChannel(10),
pod,
false)
sslCert := ssl.GetFakeSSLCert(fs)
sslCert := ssl.GetFakeSSLCert()
config := &Configuration{
FakeCertificate: sslCert,
ListenPorts: &ngx_config.ListenPorts{
@ -1136,10 +1129,9 @@ func newNGINXController(t *testing.T) *NGINXController {
}
return &NGINXController{
store: storer,
cfg: config,
command: NewNginxCommand(),
fileSystem: fs,
store: storer,
cfg: config,
command: NewNginxCommand(),
}
}

View file

@ -44,7 +44,6 @@ import (
"k8s.io/client-go/tools/record"
"k8s.io/client-go/util/flowcontrol"
"k8s.io/klog"
"k8s.io/kubernetes/pkg/util/filesystem"
adm_controler "k8s.io/ingress-nginx/internal/admission/controller"
"k8s.io/ingress-nginx/internal/file"
@ -69,12 +68,8 @@ const (
tempNginxPattern = "nginx-cfg"
)
var (
tmplPath = "/etc/nginx/template/nginx.tmpl"
)
// NewNGINXController creates a new NGINX Ingress controller.
func NewNGINXController(config *Configuration, mc metric.Collector, fs file.Filesystem) *NGINXController {
func NewNGINXController(config *Configuration, mc metric.Collector) *NGINXController {
eventBroadcaster := record.NewBroadcaster()
eventBroadcaster.StartLogging(klog.Infof)
eventBroadcaster.StartRecordingToSink(&v1core.EventSinkImpl{
@ -102,8 +97,6 @@ func NewNGINXController(config *Configuration, mc metric.Collector, fs file.File
stopLock: &sync.Mutex{},
fileSystem: fs,
runningConfig: new(ingress.Configuration),
Proxy: &TCPProxy{},
@ -135,7 +128,6 @@ func NewNGINXController(config *Configuration, mc metric.Collector, fs file.File
config.DefaultSSLCertificate,
config.ResyncPeriod,
config.Client,
fs,
n.updateCh,
pod,
config.DisableCatchAll)
@ -156,7 +148,7 @@ func NewNGINXController(config *Configuration, mc metric.Collector, fs file.File
}
onTemplateChange := func() {
template, err := ngx_template.NewTemplate(tmplPath, fs)
template, err := ngx_template.NewTemplate(nginx.TemplatePath)
if err != nil {
// this error is different from the rest because it must be clear why nginx is not working
klog.Errorf(`
@ -172,21 +164,16 @@ Error loading new template: %v
n.syncQueue.EnqueueTask(task.GetDummyObject("template-change"))
}
ngxTpl, err := ngx_template.NewTemplate(tmplPath, fs)
ngxTpl, err := ngx_template.NewTemplate(nginx.TemplatePath)
if err != nil {
klog.Fatalf("Invalid NGINX configuration template: %v", err)
}
n.t = ngxTpl
if _, ok := fs.(filesystem.DefaultFs); !ok {
// do not setup watchers on tests
return n
}
_, err = watch.NewFileWatcher(tmplPath, onTemplateChange)
_, err = watch.NewFileWatcher(nginx.TemplatePath, onTemplateChange)
if err != nil {
klog.Fatalf("Error creating file watcher for %v: %v", tmplPath, err)
klog.Fatalf("Error creating file watcher for %v: %v", nginx.TemplatePath, err)
}
filesToWatch := []string{}
@ -260,8 +247,6 @@ type NGINXController struct {
store store.Storer
fileSystem filesystem.Filesystem
metricCollector metric.Collector
validationWebhookServer *http.Server
@ -582,7 +567,7 @@ func (n NGINXController) generateTemplate(cfg ngx_config.Configuration, ingressC
nsSecName := strings.Replace(secretName, "/", "-", -1)
dh, ok := secret.Data["dhparam.pem"]
if ok {
pemFileName, err := ssl.AddOrUpdateDHParam(nsSecName, dh, n.fileSystem)
pemFileName, err := ssl.AddOrUpdateDHParam(nsSecName, dh)
if err != nil {
klog.Warningf("Error adding or updating dhparam file %v: %v", nsSecName, err)
} else {
@ -594,25 +579,26 @@ func (n NGINXController) generateTemplate(cfg ngx_config.Configuration, ingressC
cfg.SSLDHParam = sslDHParam
cfg.DefaultSSLCertificate = n.getDefaultSSLCertificate()
tc := ngx_config.TemplateConfig{
ProxySetHeaders: setHeaders,
AddHeaders: addHeaders,
BacklogSize: sysctlSomaxconn(),
Backends: ingressCfg.Backends,
PassthroughBackends: ingressCfg.PassthroughBackends,
Servers: ingressCfg.Servers,
TCPBackends: ingressCfg.TCPEndpoints,
UDPBackends: ingressCfg.UDPEndpoints,
Cfg: cfg,
IsIPV6Enabled: n.isIPV6Enabled && !cfg.DisableIpv6,
NginxStatusIpv4Whitelist: cfg.NginxStatusIpv4Whitelist,
NginxStatusIpv6Whitelist: cfg.NginxStatusIpv6Whitelist,
RedirectServers: buildRedirects(ingressCfg.Servers),
IsSSLPassthroughEnabled: n.cfg.EnableSSLPassthrough,
ListenPorts: n.cfg.ListenPorts,
PublishService: n.GetPublishService(),
EnableDynamicCertificates: ngx_config.EnableDynamicCertificates,
EnableMetrics: n.cfg.EnableMetrics,
ProxySetHeaders: setHeaders,
AddHeaders: addHeaders,
BacklogSize: sysctlSomaxconn(),
Backends: ingressCfg.Backends,
PassthroughBackends: ingressCfg.PassthroughBackends,
Servers: ingressCfg.Servers,
TCPBackends: ingressCfg.TCPEndpoints,
UDPBackends: ingressCfg.UDPEndpoints,
Cfg: cfg,
IsIPV6Enabled: n.isIPV6Enabled && !cfg.DisableIpv6,
NginxStatusIpv4Whitelist: cfg.NginxStatusIpv4Whitelist,
NginxStatusIpv6Whitelist: cfg.NginxStatusIpv6Whitelist,
RedirectServers: buildRedirects(ingressCfg.Servers),
IsSSLPassthroughEnabled: n.cfg.EnableSSLPassthrough,
ListenPorts: n.cfg.ListenPorts,
PublishService: n.GetPublishService(),
EnableMetrics: n.cfg.EnableMetrics,
HealthzURI: nginx.HealthPath,
PID: nginx.PID,
@ -805,7 +791,9 @@ func clearCertificates(config *ingress.Configuration) {
var clearedServers []*ingress.Server
for _, server := range config.Servers {
copyOfServer := *server
copyOfServer.SSLCert = ingress.SSLCert{PemFileName: copyOfServer.SSLCert.PemFileName}
if copyOfServer.SSLCert != nil {
copyOfServer.SSLCert = &ingress.SSLCert{PemFileName: copyOfServer.SSLCert.PemFileName}
}
clearedServers = append(clearedServers, &copyOfServer)
}
config.Servers = clearedServers
@ -853,10 +841,8 @@ func (n *NGINXController) IsDynamicConfigurationEnough(pcfg *ingress.Configurati
copyOfRunningConfig.ControllerPodsCount = 0
copyOfPcfg.ControllerPodsCount = 0
if ngx_config.EnableDynamicCertificates {
clearCertificates(&copyOfRunningConfig)
clearCertificates(&copyOfPcfg)
}
clearCertificates(&copyOfRunningConfig)
clearCertificates(&copyOfPcfg)
return copyOfRunningConfig.Equal(&copyOfPcfg)
}
@ -951,11 +937,9 @@ func configureDynamically(pcfg *ingress.Configuration) error {
return fmt.Errorf("unexpected error code: %d", statusCode)
}
if ngx_config.EnableDynamicCertificates {
err = configureCertificates(pcfg)
if err != nil {
return err
}
err = configureCertificates(pcfg)
if err != nil {
return err
}
return nil
@ -988,16 +972,16 @@ func updateStreamConfiguration(streams []ingress.Backend) error {
// configureCertificates JSON encodes certificates and POSTs it to an internal HTTP endpoint
// that is handled by Lua
func configureCertificates(pcfg *ingress.Configuration) error {
var servers []*ingress.Server
servers := make([]*ingress.Server, 0)
for _, server := range pcfg.Servers {
if server.SSLCert.PemCertKey == "" {
if server.SSLCert == nil {
continue
}
servers = append(servers, &ingress.Server{
Hostname: server.Hostname,
SSLCert: ingress.SSLCert{
SSLCert: &ingress.SSLCert{
PemCertKey: server.SSLCert.PemCertKey,
},
})
@ -1005,7 +989,7 @@ func configureCertificates(pcfg *ingress.Configuration) error {
if server.Alias != "" && ssl.IsValidHostname(server.Alias, server.SSLCert.CN) {
servers = append(servers, &ingress.Server{
Hostname: server.Alias,
SSLCert: ingress.SSLCert{
SSLCert: &ingress.SSLCert{
PemCertKey: server.SSLCert.PemCertKey,
},
})
@ -1014,13 +998,13 @@ func configureCertificates(pcfg *ingress.Configuration) error {
redirects := buildRedirects(pcfg.Servers)
for _, redirect := range redirects {
if redirect.SSLCert.PemCertKey == "" {
if redirect.SSLCert == nil {
continue
}
servers = append(servers, &ingress.Server{
Hostname: redirect.From,
SSLCert: ingress.SSLCert{
SSLCert: &ingress.SSLCert{
PemCertKey: redirect.SSLCert.PemCertKey,
},
})
@ -1131,7 +1115,7 @@ func cleanTempNginxCfg() error {
type redirect struct {
From string
To string
SSLCert ingress.SSLCert
SSLCert *ingress.SSLCert
}
func buildRedirects(servers []*ingress.Server) []*redirect {
@ -1175,7 +1159,7 @@ func buildRedirects(servers []*ingress.Server) []*redirect {
To: to,
}
if srv.SSLCert.PemSHA != "" {
if srv.SSLCert != nil {
if ssl.IsValidHostname(from, srv.SSLCert.CN) {
r.SSLCert = srv.SSLCert
} else {

View file

@ -32,14 +32,10 @@ import (
apiv1 "k8s.io/api/core/v1"
"k8s.io/ingress-nginx/internal/ingress"
ngx_config "k8s.io/ingress-nginx/internal/ingress/controller/config"
"k8s.io/ingress-nginx/internal/nginx"
)
func TestIsDynamicConfigurationEnough(t *testing.T) {
ngx_config.EnableDynamicCertificates = false
defer func() { ngx_config.EnableDynamicCertificates = true }()
backends := []*ingress.Backend{{
Name: "fakenamespace-myapp-80",
Endpoints: []ingress.Endpoint{
@ -62,7 +58,7 @@ func TestIsDynamicConfigurationEnough(t *testing.T) {
Backend: "fakenamespace-myapp-80",
},
},
SSLCert: ingress.SSLCert{
SSLCert: &ingress.SSLCert{
PemCertKey: "fake-certificate",
},
}}
@ -98,8 +94,6 @@ func TestIsDynamicConfigurationEnough(t *testing.T) {
Servers: servers,
}
ngx_config.EnableDynamicCertificates = true
if !n.IsDynamicConfigurationEnough(newConfig) {
t.Errorf("Expected to be dynamically configurable when only backends change")
}
@ -112,7 +106,7 @@ func TestIsDynamicConfigurationEnough(t *testing.T) {
Backend: "fakenamespace-myapp-80",
},
},
SSLCert: ingress.SSLCert{
SSLCert: &ingress.SSLCert{
PemCertKey: "fake-certificate",
},
}}
@ -201,6 +195,12 @@ func TestConfigureDynamically(t *testing.T) {
t.Errorf("controllerPodsCount should be present in JSON content: %v", body)
}
}
case "/configuration/servers":
{
if !strings.Contains(body, "[]") {
t.Errorf("controllerPodsCount should be present in JSON content: %v", body)
}
}
default:
t.Errorf("unknown request to %s", r.URL.Path)
}
@ -246,9 +246,6 @@ func TestConfigureDynamically(t *testing.T) {
ControllerPodsCount: 2,
}
ngx_config.EnableDynamicCertificates = false
defer func() { ngx_config.EnableDynamicCertificates = true }()
err = configureDynamically(commonConfig)
if err != nil {
t.Errorf("unexpected error posting dynamic configuration: %v", err)
@ -276,7 +273,7 @@ func TestConfigureCertificates(t *testing.T) {
servers := []*ingress.Server{{
Hostname: "myapp.fake",
SSLCert: ingress.SSLCert{
SSLCert: &ingress.SSLCert{
PemCertKey: "fake-cert",
},
}}

View file

@ -17,17 +17,20 @@ limitations under the License.
package store
import (
"crypto/sha1"
"encoding/hex"
"fmt"
"strings"
"k8s.io/klog"
"github.com/pkg/errors"
apiv1 "k8s.io/api/core/v1"
networking "k8s.io/api/networking/v1beta1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/ingress-nginx/internal/file"
"k8s.io/ingress-nginx/internal/ingress"
ngx_config "k8s.io/ingress-nginx/internal/ingress/controller/config"
"k8s.io/ingress-nginx/internal/net/ssl"
)
@ -39,7 +42,6 @@ func (s *k8sStore) syncSecret(key string) {
klog.V(3).Infof("Syncing Secret %q", key)
// TODO: getPemCertificate should not write to disk to avoid unnecessary overhead
cert, err := s.getPemCertificate(key)
if err != nil {
if !isErrSecretForAuth(err) {
@ -92,6 +94,7 @@ func (s *k8sStore) getPemCertificate(secretName string) (*ingress.SSLCert, error
if cert == nil {
return nil, fmt.Errorf("key 'tls.crt' missing from Secret %q", secretName)
}
if key == nil {
return nil, fmt.Errorf("key 'tls.key' missing from Secret %q", secretName)
}
@ -101,15 +104,16 @@ func (s *k8sStore) getPemCertificate(secretName string) (*ingress.SSLCert, error
return nil, fmt.Errorf("unexpected error creating SSL Cert: %v", err)
}
if !ngx_config.EnableDynamicCertificates || len(ca) > 0 {
err = ssl.StoreSSLCertOnDisk(s.filesystem, nsSecName, sslCert)
if len(ca) > 0 {
path, err := ssl.StoreSSLCertOnDisk(nsSecName, sslCert)
if err != nil {
return nil, fmt.Errorf("error while storing certificate and key: %v", err)
}
}
if len(ca) > 0 {
err = ssl.ConfigureCACertWithCertAndKey(s.filesystem, nsSecName, ca, sslCert)
sslCert.CAFileName = path
sslCert.CASHA = file.SHA1(path)
err = ssl.ConfigureCACertWithCertAndKey(nsSecName, ca, sslCert)
if err != nil {
return nil, fmt.Errorf("error configuring CA certificate: %v", err)
}
@ -120,14 +124,13 @@ func (s *k8sStore) getPemCertificate(secretName string) (*ingress.SSLCert, error
msg += " and authentication"
}
klog.V(3).Info(msg)
} else if len(ca) > 0 {
sslCert, err = ssl.CreateCACert(ca)
if err != nil {
return nil, fmt.Errorf("unexpected error creating SSL Cert: %v", err)
}
err = ssl.ConfigureCACert(s.filesystem, nsSecName, ca, sslCert)
err = ssl.ConfigureCACert(nsSecName, ca, sslCert)
if err != nil {
return nil, fmt.Errorf("error configuring CA certificate: %v", err)
}
@ -135,7 +138,6 @@ func (s *k8sStore) getPemCertificate(secretName string) (*ingress.SSLCert, error
// makes this secret in 'syncSecret' to be used for Certificate Authentication
// this does not enable Certificate Authentication
klog.V(3).Infof("Configuring Secret %q for TLS authentication", secretName)
} else {
if auth != nil {
return nil, ErrSecretForAuth
@ -147,6 +149,21 @@ func (s *k8sStore) getPemCertificate(secretName string) (*ingress.SSLCert, error
sslCert.Name = secret.Name
sslCert.Namespace = secret.Namespace
hasher := sha1.New()
hasher.Write(sslCert.Certificate.Raw)
sslCert.PemSHA = hex.EncodeToString(hasher.Sum(nil))
// the default SSL certificate needs to be present on disk
if secretName == s.defaultSSLCertificate {
path, err := ssl.StoreSSLCertOnDisk(nsSecName, sslCert)
if err != nil {
return nil, errors.Wrap(err, "storing default SSL Certificate")
}
sslCert.PemFileName = path
}
return sslCert, nil
}

View file

@ -152,9 +152,9 @@ func (e NotExistsError) Error() string {
// Run initiates the synchronization of the informers against the API server.
func (i *Informer) Run(stopCh chan struct{}) {
go i.Secret.Run(stopCh)
go i.Endpoint.Run(stopCh)
go i.Service.Run(stopCh)
go i.Secret.Run(stopCh)
go i.ConfigMap.Run(stopCh)
go i.Pod.Run(stopCh)
@ -165,6 +165,7 @@ func (i *Informer) Run(stopCh chan struct{}) {
i.Service.HasSynced,
i.Secret.HasSynced,
i.ConfigMap.HasSynced,
i.Pod.HasSynced,
) {
runtime.HandleError(fmt.Errorf("timed out waiting for caches to sync"))
}
@ -208,8 +209,6 @@ type k8sStore struct {
// secret in the annotations.
secretIngressMap ObjectRefMap
filesystem file.Filesystem
// updateCh
updateCh *channels.RingChannel
@ -229,7 +228,6 @@ func New(
namespace, configmap, tcp, udp, defaultSSLCertificate string,
resyncPeriod time.Duration,
client clientset.Interface,
fs file.Filesystem,
updateCh *channels.RingChannel,
pod *k8s.PodInfo,
disableCatchAll bool) Storer {
@ -238,7 +236,6 @@ func New(
informers: &Informer{},
listers: &Lister{},
sslStore: NewSSLCertTracker(),
filesystem: fs,
updateCh: updateCh,
backendConfig: ngx_config.NewDefault(),
syncSecretMu: &sync.Mutex{},
@ -494,6 +491,7 @@ func New(
}
store.syncIngress(ing)
}
updateCh.In() <- Event{
Type: DeleteEvent,
Obj: obj,
@ -813,7 +811,7 @@ func (s *k8sStore) GetAuthCertificate(name string) (*resolver.AuthSSLCert, error
return &resolver.AuthSSLCert{
Secret: name,
CAFileName: cert.CAFileName,
PemSHA: cert.PemSHA,
CASHA: cert.CASHA,
}, nil
}

View file

@ -38,10 +38,8 @@ import (
"k8s.io/client-go/tools/cache"
"sigs.k8s.io/controller-runtime/pkg/envtest"
"k8s.io/ingress-nginx/internal/file"
"k8s.io/ingress-nginx/internal/ingress"
"k8s.io/ingress-nginx/internal/ingress/annotations/parser"
ngx_config "k8s.io/ingress-nginx/internal/ingress/controller/config"
"k8s.io/ingress-nginx/internal/k8s"
"k8s.io/ingress-nginx/test/e2e/framework"
)
@ -87,7 +85,6 @@ func TestStore(t *testing.T) {
}
}(updateCh)
fs := newFS(t)
storer := New(
ns,
fmt.Sprintf("%v/config", ns),
@ -96,7 +93,6 @@ func TestStore(t *testing.T) {
"",
10*time.Minute,
clientSet,
fs,
updateCh,
pod,
false)
@ -167,7 +163,6 @@ func TestStore(t *testing.T) {
}
}(updateCh)
fs := newFS(t)
storer := New(
ns,
fmt.Sprintf("%v/config", ns),
@ -176,7 +171,6 @@ func TestStore(t *testing.T) {
"",
10*time.Minute,
clientSet,
fs,
updateCh,
pod,
false)
@ -317,7 +311,6 @@ func TestStore(t *testing.T) {
}
}(updateCh)
fs := newFS(t)
storer := New(
ns,
fmt.Sprintf("%v/config", ns),
@ -326,7 +319,6 @@ func TestStore(t *testing.T) {
"",
10*time.Minute,
clientSet,
fs,
updateCh,
pod,
false)
@ -423,7 +415,6 @@ func TestStore(t *testing.T) {
}
}(updateCh)
fs := newFS(t)
storer := New(
ns,
fmt.Sprintf("%v/config", ns),
@ -432,7 +423,6 @@ func TestStore(t *testing.T) {
"",
10*time.Minute,
clientSet,
fs,
updateCh,
pod,
false)
@ -512,7 +502,6 @@ func TestStore(t *testing.T) {
}
}(updateCh)
fs := newFS(t)
storer := New(
ns,
fmt.Sprintf("%v/config", ns),
@ -521,7 +510,6 @@ func TestStore(t *testing.T) {
"",
10*time.Minute,
clientSet,
fs,
updateCh,
pod,
false)
@ -623,7 +611,6 @@ func TestStore(t *testing.T) {
}
}(updateCh)
fs := newFS(t)
storer := New(
ns,
fmt.Sprintf("%v/config", ns),
@ -632,7 +619,6 @@ func TestStore(t *testing.T) {
"",
10*time.Minute,
clientSet,
fs,
updateCh,
pod,
false)
@ -701,39 +687,6 @@ func TestStore(t *testing.T) {
if err != nil {
t.Errorf("error creating secret: %v", err)
}
t.Run("should exists a secret in the local store and filesystem", func(t *testing.T) {
ngx_config.EnableDynamicCertificates = false
defer func() { ngx_config.EnableDynamicCertificates = true }()
err := framework.WaitForSecretInNamespace(clientSet, ns, name)
if err != nil {
t.Errorf("error waiting for secret: %v", err)
}
time.Sleep(5 * time.Second)
pemFile := fmt.Sprintf("%v/%v-%v.pem", file.DefaultSSLDirectory, ns, name)
err = framework.WaitForFileInFS(pemFile, fs)
if err != nil {
t.Errorf("error waiting for file to exist on the file system: %v", err)
}
secretName := fmt.Sprintf("%v/%v", ns, name)
sslCert, err := storer.GetLocalSSLCert(secretName)
if err != nil {
t.Errorf("error reading local secret %v: %v", secretName, err)
}
if sslCert == nil {
t.Errorf("expected a secret but none returned")
}
pemSHA := file.SHA1(pemFile)
if sslCert.PemSHA != pemSHA {
t.Errorf("SHA of secret on disk differs from local secret store (%v != %v)", pemSHA, sslCert.PemSHA)
}
})
})
// test add ingress with secret it doesn't exists and then add secret
@ -821,22 +774,9 @@ func deleteIngress(ingress *networking.Ingress, clientSet kubernetes.Interface,
t.Logf("Ingress %+v deleted", ingress)
}
func newFS(t *testing.T) file.Filesystem {
fs, err := file.NewFakeFS()
if err != nil {
t.Fatalf("error creating filesystem: %v", err)
}
return fs
}
// newStore creates a new mock object store for tests which do not require the
// use of Informers.
func newStore(t *testing.T) *k8sStore {
fs, err := file.NewFakeFS()
if err != nil {
t.Fatalf("error: %v", err)
}
pod := &k8s.PodInfo{
Name: "ingress-1",
Namespace: v1.NamespaceDefault,
@ -853,7 +793,6 @@ func newStore(t *testing.T) *k8sStore {
Pod: PodLister{cache.NewStore(cache.MetaNamespaceKeyFunc)},
},
sslStore: NewSSLCertTracker(),
filesystem: fs,
updateCh: channels.NewRingChannel(10),
syncSecretMu: new(sync.Mutex),
backendConfigMu: new(sync.RWMutex),

View file

@ -21,6 +21,7 @@ import (
"encoding/base64"
"encoding/json"
"fmt"
"io/ioutil"
"math/rand"
"net"
"net/url"
@ -39,7 +40,6 @@ import (
"k8s.io/apimachinery/pkg/util/sets"
"k8s.io/klog"
"k8s.io/ingress-nginx/internal/file"
"k8s.io/ingress-nginx/internal/ingress"
"k8s.io/ingress-nginx/internal/ingress/annotations/influxdb"
"k8s.io/ingress-nginx/internal/ingress/annotations/ratelimit"
@ -67,8 +67,8 @@ type Template struct {
//NewTemplate returns a new Template instance or an
//error if the specified template file contains errors
func NewTemplate(file string, fs file.Filesystem) (*Template, error) {
data, err := fs.ReadFile(file)
func NewTemplate(file string) (*Template, error) {
data, err := ioutil.ReadFile(file)
if err != nil {
return nil, errors.Wrapf(err, "unexpected error reading template %v", file)
}
@ -346,7 +346,7 @@ func locationConfigForLua(l interface{}, s interface{}, a interface{}) string {
return "{}"
}
forceSSLRedirect := location.Rewrite.ForceSSLRedirect || len(server.SSLCert.PemFileName) > 0 && location.Rewrite.SSLRedirect
forceSSLRedirect := location.Rewrite.ForceSSLRedirect || (server.SSLCert != nil && location.Rewrite.SSLRedirect)
forceSSLRedirect = forceSSLRedirect && !isLocationInLocationList(l, all.Cfg.NoTLSRedirectLocations)
return fmt.Sprintf(`{
@ -1177,6 +1177,12 @@ func buildHTTPSListener(t interface{}, s interface{}) string {
return ""
}
/*
if server.SSLCert == nil && server.Hostname != "_" {
return ""
}
*/
co := commonListenOptions(tc, hostname)
addrV4 := []string{""}

View file

@ -17,20 +17,20 @@ limitations under the License.
package template
import (
"encoding/base64"
"fmt"
"io/ioutil"
"net"
"os"
"path"
"path/filepath"
"reflect"
"strings"
"testing"
"encoding/base64"
"fmt"
jsoniter "github.com/json-iterator/go"
networking "k8s.io/api/networking/v1beta1"
"k8s.io/ingress-nginx/internal/file"
"k8s.io/ingress-nginx/internal/ingress"
"k8s.io/ingress-nginx/internal/ingress/annotations/authreq"
"k8s.io/ingress-nginx/internal/ingress/annotations/influxdb"
@ -39,8 +39,18 @@ import (
"k8s.io/ingress-nginx/internal/ingress/annotations/ratelimit"
"k8s.io/ingress-nginx/internal/ingress/annotations/rewrite"
"k8s.io/ingress-nginx/internal/ingress/controller/config"
"k8s.io/ingress-nginx/internal/nginx"
)
func init() {
// the default value of nginx.TemplatePath assumes the template exists in
// the root filesystem and not in the rootfs directory
path, err := filepath.Abs(filepath.Join("../../../../rootfs/", nginx.TemplatePath))
if err == nil {
nginx.TemplatePath = path
}
}
var (
// TODO: add tests for SSLPassthrough
tmplFuncTestcases = map[string]struct {
@ -435,16 +445,13 @@ func TestTemplateWithData(t *testing.T) {
dat.ListenPorts = &config.ListenPorts{}
}
fs, err := file.NewFakeFS()
if err != nil {
t.Fatalf("unexpected error: %v", err)
}
ngxTpl, err := NewTemplate("/etc/nginx/template/nginx.tmpl", fs)
ngxTpl, err := NewTemplate(nginx.TemplatePath)
if err != nil {
t.Errorf("invalid NGINX template: %v", err)
}
dat.Cfg.DefaultSSLCertificate = &ingress.SSLCert{}
rt, err := ngxTpl.Write(dat)
if err != nil {
t.Errorf("invalid NGINX template: %v", err)
@ -479,12 +486,7 @@ func BenchmarkTemplateWithData(b *testing.B) {
b.Errorf("unexpected error unmarshalling json: %v", err)
}
fs, err := file.NewFakeFS()
if err != nil {
b.Fatalf("unexpected error: %v", err)
}
ngxTpl, err := NewTemplate("/etc/nginx/template/nginx.tmpl", fs)
ngxTpl, err := NewTemplate(nginx.TemplatePath)
if err != nil {
b.Errorf("invalid NGINX template: %v", err)
}