Cleanup
This commit is contained in:
parent
e68cf185cc
commit
3fe8524318
8 changed files with 100 additions and 783 deletions
|
@ -189,7 +189,7 @@ func setupSSLProxy(sslPort, proxyPort int, n *controller.NGINXController) {
|
|||
var conn net.Conn
|
||||
var err error
|
||||
|
||||
if n.IsProxyProtocolEnabled {
|
||||
if n.IsProxyProtocolEnabled() {
|
||||
// we need to wrap the listener in order to decode
|
||||
// proxy protocol before handling the connection
|
||||
conn, err = proxyList.Accept()
|
||||
|
|
|
@ -1,197 +0,0 @@
|
|||
/*
|
||||
Copyright 2015 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package controller
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"strings"
|
||||
|
||||
"github.com/golang/glog"
|
||||
"github.com/imdario/mergo"
|
||||
|
||||
apiv1 "k8s.io/api/core/v1"
|
||||
extensions "k8s.io/api/extensions/v1beta1"
|
||||
|
||||
"k8s.io/ingress-nginx/internal/ingress"
|
||||
"k8s.io/ingress-nginx/internal/ingress/annotations/class"
|
||||
"k8s.io/ingress-nginx/internal/ingress/annotations/parser"
|
||||
"k8s.io/ingress-nginx/internal/net/ssl"
|
||||
)
|
||||
|
||||
// syncSecret keeps in sync Secrets used by Ingress rules with the files on
|
||||
// disk to allow copy of the content of the secret to disk to be used
|
||||
// by external processes.
|
||||
func (ic *NGINXController) syncSecret(key string) {
|
||||
glog.V(3).Infof("starting syncing of secret %v", key)
|
||||
|
||||
cert, err := ic.getPemCertificate(key)
|
||||
if err != nil {
|
||||
glog.Warningf("error obtaining PEM from secret %v: %v", key, err)
|
||||
return
|
||||
}
|
||||
|
||||
// create certificates and add or update the item in the store
|
||||
cur, exists := ic.sslCertTracker.Get(key)
|
||||
if exists {
|
||||
s := cur.(*ingress.SSLCert)
|
||||
if s.Equal(cert) {
|
||||
// no need to update
|
||||
return
|
||||
}
|
||||
glog.Infof("updating secret %v in the local store", key)
|
||||
ic.sslCertTracker.Update(key, cert)
|
||||
// this update must trigger an update
|
||||
// (like an update event from a change in Ingress)
|
||||
ic.syncQueue.Enqueue(&extensions.Ingress{})
|
||||
return
|
||||
}
|
||||
|
||||
glog.Infof("adding secret %v to the local store", key)
|
||||
ic.sslCertTracker.Add(key, cert)
|
||||
// this update must trigger an update
|
||||
// (like an update event from a change in Ingress)
|
||||
ic.syncQueue.Enqueue(&extensions.Ingress{})
|
||||
}
|
||||
|
||||
// getPemCertificate receives a secret, and creates a ingress.SSLCert as return.
|
||||
// It parses the secret and verifies if it's a keypair, or a 'ca.crt' secret only.
|
||||
func (ic *NGINXController) getPemCertificate(secretName string) (*ingress.SSLCert, error) {
|
||||
secret, err := ic.store.GetSecret(secretName)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error retrieving secret %v: %v", secretName, err)
|
||||
}
|
||||
|
||||
cert, okcert := secret.Data[apiv1.TLSCertKey]
|
||||
key, okkey := secret.Data[apiv1.TLSPrivateKeyKey]
|
||||
ca := secret.Data["ca.crt"]
|
||||
|
||||
// namespace/secretName -> namespace-secretName
|
||||
nsSecName := strings.Replace(secretName, "/", "-", -1)
|
||||
|
||||
var s *ingress.SSLCert
|
||||
if okcert && okkey {
|
||||
if cert == nil {
|
||||
return nil, fmt.Errorf("secret %v has no 'tls.crt'", secretName)
|
||||
}
|
||||
if key == nil {
|
||||
return nil, fmt.Errorf("secret %v has no 'tls.key'", secretName)
|
||||
}
|
||||
|
||||
// If 'ca.crt' is also present, it will allow this secret to be used in the
|
||||
// 'nginx.ingress.kubernetes.io/auth-tls-secret' annotation
|
||||
s, err = ssl.AddOrUpdateCertAndKey(nsSecName, cert, key, ca, ic.fileSystem)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("unexpected error creating pem file: %v", err)
|
||||
}
|
||||
|
||||
glog.V(3).Infof("found 'tls.crt' and 'tls.key', configuring %v as a TLS Secret (CN: %v)", secretName, s.CN)
|
||||
if ca != nil {
|
||||
glog.V(3).Infof("found 'ca.crt', secret %v can also be used for Certificate Authentication", secretName)
|
||||
}
|
||||
|
||||
} else if ca != nil {
|
||||
s, err = ssl.AddCertAuth(nsSecName, ca, ic.fileSystem)
|
||||
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("unexpected error creating pem file: %v", err)
|
||||
}
|
||||
|
||||
// makes this secret in 'syncSecret' to be used for Certificate Authentication
|
||||
// this does not enable Certificate Authentication
|
||||
glog.V(3).Infof("found only 'ca.crt', configuring %v as an Certificate Authentication Secret", secretName)
|
||||
|
||||
} else {
|
||||
return nil, fmt.Errorf("no keypair or CA cert could be found in %v", secretName)
|
||||
}
|
||||
|
||||
s.Name = secret.Name
|
||||
s.Namespace = secret.Namespace
|
||||
return s, nil
|
||||
}
|
||||
|
||||
func (ic *NGINXController) checkSSLChainIssues() {
|
||||
for _, secretName := range ic.sslCertTracker.ListKeys() {
|
||||
s, _ := ic.sslCertTracker.Get(secretName)
|
||||
secret := s.(*ingress.SSLCert)
|
||||
|
||||
if secret.FullChainPemFileName != "" {
|
||||
// chain already checked
|
||||
continue
|
||||
}
|
||||
|
||||
data, err := ssl.FullChainCert(secret.PemFileName, ic.fileSystem)
|
||||
if err != nil {
|
||||
glog.Errorf("unexpected error generating SSL certificate with full intermediate chain CA certs: %v", err)
|
||||
continue
|
||||
}
|
||||
|
||||
fullChainPemFileName := fmt.Sprintf("%v/%v-%v-full-chain.pem", ingress.DefaultSSLDirectory, secret.Namespace, secret.Name)
|
||||
err = ioutil.WriteFile(fullChainPemFileName, data, 0655)
|
||||
if err != nil {
|
||||
glog.Errorf("unexpected error creating SSL certificate: %v", err)
|
||||
continue
|
||||
}
|
||||
|
||||
dst := &ingress.SSLCert{}
|
||||
|
||||
err = mergo.MergeWithOverwrite(dst, secret)
|
||||
if err != nil {
|
||||
glog.Errorf("unexpected error creating SSL certificate: %v", err)
|
||||
continue
|
||||
}
|
||||
|
||||
dst.FullChainPemFileName = fullChainPemFileName
|
||||
|
||||
glog.Infof("updating local copy of ssl certificate %v with missing intermediate CA certs", secretName)
|
||||
ic.sslCertTracker.Update(secretName, dst)
|
||||
// this update must trigger an update
|
||||
// (like an update event from a change in Ingress)
|
||||
ic.syncQueue.Enqueue(&extensions.Ingress{})
|
||||
}
|
||||
}
|
||||
|
||||
// checkMissingSecrets verify if one or more ingress rules contains a reference
|
||||
// to a secret that is not present in the local secret store.
|
||||
// In this case we call syncSecret.
|
||||
func (ic *NGINXController) checkMissingSecrets() {
|
||||
for _, ing := range ic.store.ListIngresses() {
|
||||
if !class.IsValid(ing) {
|
||||
continue
|
||||
}
|
||||
|
||||
for _, tls := range ing.Spec.TLS {
|
||||
if tls.SecretName == "" {
|
||||
continue
|
||||
}
|
||||
|
||||
key := fmt.Sprintf("%v/%v", ing.Namespace, tls.SecretName)
|
||||
if _, ok := ic.sslCertTracker.Get(key); !ok {
|
||||
ic.syncSecret(key)
|
||||
}
|
||||
}
|
||||
|
||||
key, _ := parser.GetStringAnnotation("auth-tls-secret", ing)
|
||||
if key == "" {
|
||||
continue
|
||||
}
|
||||
|
||||
if _, ok := ic.sslCertTracker.Get(key); !ok {
|
||||
ic.syncSecret(key)
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,234 +0,0 @@
|
|||
/*
|
||||
Copyright 2017 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package controller
|
||||
|
||||
import (
|
||||
"encoding/base64"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
|
||||
apiv1 "k8s.io/api/core/v1"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
testclient "k8s.io/client-go/kubernetes/fake"
|
||||
cache_client "k8s.io/client-go/tools/cache"
|
||||
|
||||
"k8s.io/ingress-nginx/internal/ingress"
|
||||
"k8s.io/ingress-nginx/internal/ingress/store"
|
||||
)
|
||||
|
||||
const (
|
||||
// openssl req -x509 -nodes -days 3650 -newkey rsa:2048 -keyout tls.key -out tls.crt -subj "/CN=nginxsvc/O=nginxsvc"
|
||||
tlsCrt = "LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSURIekNDQWdlZ0F3SUJBZ0lKQU1KZld6Mm81cWVnTUEwR0NTcUdTSWIzRFFFQkN3VUFNQ1l4RVRBUEJnTlYKQkFNTUNHNW5hVzU0YzNaak1SRXdEd1lEVlFRS0RBaHVaMmx1ZUhOMll6QWVGdzB4TnpBME1URXdNakF3TlRCYQpGdzB5TnpBME1Ea3dNakF3TlRCYU1DWXhFVEFQQmdOVkJBTU1DRzVuYVc1NGMzWmpNUkV3RHdZRFZRUUtEQWh1CloybHVlSE4yWXpDQ0FTSXdEUVlKS29aSWh2Y05BUUVCQlFBRGdnRVBBRENDQVFvQ2dnRUJBTUgzVTYvY3ArODAKU3hJRjltSnlUcGI5RzBodnhsM0JMaGdQWDBTWjZ3d1lISGJXeTh2dmlCZjVwWTdvVHd0b2FPaTN1VFNsL2RtVwpvUi9XNm9GVWM5a2l6NlNXc3p6YWRXL2l2Q21LMmxOZUFVc2gvaXY0aTAvNXlreDJRNXZUT2tVL1dra2JPOW1OCjdSVTF0QW1KT3M0T1BVc3hZZkw2cnJJUzZPYktHS2UvYUVkek9QS2NPMDJ5NUxDeHM0TFhhWDIzU1l6TG1XYVAKYVZBallrN1NRZm1xUm5mYlF4RWlpaDFQWTFRRXgxWWs0RzA0VmtHUitrSVVMaWF0L291ZjQxY0dXRTZHMTF4NQpkV1BHeS9XcGtqRGlaM0UwekdNZnJBVUZibnErN1dhRTJCRzVoUVV3ZG9SQUtWTnMzaVhLRlRkT3hoRll5bnBwCjA3cDJVNS96ZHRrQ0F3RUFBYU5RTUU0d0hRWURWUjBPQkJZRUZCL2U5UnVna0Mwc0VNTTZ6enRCSjI1U1JxalMKTUI4R0ExVWRJd1FZTUJhQUZCL2U5UnVna0Mwc0VNTTZ6enRCSjI1U1JxalNNQXdHQTFVZEV3UUZNQU1CQWY4dwpEUVlKS29aSWh2Y05BUUVMQlFBRGdnRUJBRys4MXdaSXRuMmFWSlFnejNkNmJvZW1nUXhSSHpaZDhNc1IrdFRvCnpJLy9ac1Nwc2FDR3F0TkdTaHVGKzB3TVZ4NjlpQ3lJTnJJb2J4K29NTHBsQzFQSk9uektSUUdvZEhYNFZaSUwKVlhxSFd2VStjK3ZtT0QxUEt3UjcwRi9rTXk2Yk4xMVI2amhIZ3RPZGdLKzdRczhRMVlUSC9RS2dMd3RJTFRHRwpTZlYxWFlmbnF1TXlZKzFzck00U3ZRSmRzdmFUQmJkZHE2RllpdjhXZFpIaG51ZGlSODdZcFgzOUlTSlFkOXF2CnR6OGthZTVqQVFEUWFiZnFsVWZNT1hmUnhyei96S2NvN3dMeWFMWTh1eVhEWUVIZmlHRWdablV0RjgxVlhDZUIKeU80UERBR0FuVmlXTndFM0NZcGI4RkNGelMyaVVVMDJaQWJRajlvUnYyUWNON1E9Ci0tLS0tRU5EIENFUlRJRklDQVRFLS0tLS0K"
|
||||
tlsKey = "LS0tLS1CRUdJTiBQUklWQVRFIEtFWS0tLS0tCk1JSUV2Z0lCQURBTkJna3Foa2lHOXcwQkFRRUZBQVNDQktnd2dnU2tBZ0VBQW9JQkFRREI5MU92M0tmdk5Fc1MKQmZaaWNrNlcvUnRJYjhaZHdTNFlEMTlFbWVzTUdCeDIxc3ZMNzRnWCthV082RThMYUdqb3Q3azBwZjNabHFFZgoxdXFCVkhQWklzK2tsck04Mm5WdjRyd3BpdHBUWGdGTElmNHIrSXRQK2NwTWRrT2IwenBGUDFwSkd6dlpqZTBWCk5iUUppVHJPRGoxTE1XSHkrcTZ5RXVqbXloaW52MmhIY3pqeW5EdE5zdVN3c2JPQzEybDl0MG1NeTVsbWoybFEKSTJKTzBrSDVxa1ozMjBNUklvb2RUMk5VQk1kV0pPQnRPRlpCa2ZwQ0ZDNG1yZjZMbitOWEJsaE9odGRjZVhWagp4c3YxcVpJdzRtZHhOTXhqSDZ3RkJXNTZ2dTFtaE5nUnVZVUZNSGFFUUNsVGJONGx5aFUzVHNZUldNcDZhZE82CmRsT2Y4M2JaQWdNQkFBRUNnZ0VBRGU1WW1XSHN3ZFpzcWQrNXdYcGFRS2Z2SkxXNmRwTmdYeVFEZ0tiWlplWDUKYldPaUFZU3pycDBra2U0SGQxZEphYVdBYk5LYk45eUV1QWUwa2hOaHVxK3dZQzdlc3JreUJCWXgwMzRBamtwTApKMzFLaHhmejBZdXNSdStialg2UFNkZnlBUnd1b1VKN1M3R3V1NXlhbDZBWU1PVmNGcHFBbjVPU0hMbFpLZnNLClN3NXZyM3NKUjNyOENNWVZoUmQ0citGam9lMXlaczJhUHl2bno5c0U3T0ZCSVRGSVBKcE4veG53VUNpWW5vSEMKV2F2TzB5RCtPeTUyN2hBQ1FwaFVMVjRaZXV2bEZwd2ZlWkZveUhnc2YrM1FxeGhpdGtJb3NGakx2Y0xlL2xjZwpSVHNRUnU5OGJNUTdSakJpYU5kaURadjBaWEMvUUMvS054SEw0bXgxTFFLQmdRRHVDY0pUM2JBZmJRY2YvSGh3CjNxRzliNE9QTXpwOTl2ajUzWU1hZHo5Vlk1dm9RR3RGeFlwbTBRVm9MR1lkQ3BHK0lXaDdVVHBMV0JUeGtMSkYKd3EwcEFmRVhmdHB0anhmcyt0OExWVUFtSXJiM2hwUjZDUjJmYjFJWVZRWUJ4dUdzN0hWMmY3NnRZMVAzSEFnNwpGTDJNTnF3ZDd5VmlsVXdSTVptcmJKV3Qwd0tCZ1FEUW1qZlgzc1NWSWZtN1FQaVQvclhSOGJMM1B3V0lNa3NOCldJTVRYeDJmaG0vd0hOL0pNdCtEK2VWbGxjSXhLMmxSYlNTQ1NwU2hzRUVsMHNxWHZUa1FFQnJxN3RFZndRWU0KbGxNbDJQb0ovV2E5c2VYSTAzWWRNeC94Vm5sbzNaUG9MUGg4UmtKekJTWkhnMlB6cCs0VmlnUklBcGdYMXo3TwpMbHg0SEVtaEl3S0JnUURES1RVdVZYL2xCQnJuV3JQVXRuT2RRU1IzNytSeENtQXZYREgxTFBlOEpxTFkxSmdlCjZFc0U2VEtwcWwwK1NrQWJ4b0JIT3QyMGtFNzdqMHJhYnpaUmZNb1NIV3N3a0RWcGtuWDBjTHpiaDNMRGxvOTkKVHFQKzUrSkRHTktIK210a3Y2bStzaFcvU3NTNHdUN3VVWjdtcXB5TEhsdGtiRXVsZlNra3B5NUJDUUtCZ0RmUwpyVk1GZUZINGI1NGV1dWJQNk5Rdi9CYVNOT2JIbnJJSmw3b2RZQTRLcWZYMXBDVnhpY01Gb3MvV2pjc2V0T1puCmNMZTFRYVVyUjZQWmp3R2dUNTd1MEdWQ1Y1QkoxVmFVKzlkTEEwNmRFMXQ4T2VQT1F2TjVkUGplalVyMDBObjIKL3VBeTVTRm1wV0hKMVh1azJ0L0V1WFNUelNQRUpEaUV5NVlRNjl0RkFvR0JBT2tDcW1jVGZGYlpPTjJRK2JqdgpvVmQvSFpLR3YrbEhqcm5maVlhODVxcUszdWJmb0FSNGppR3V3TThqc3hZZW8vb0hQdHJDTkxINndsYlZNTUFGCmlRZG80ZUF3S0xxRHo1MUx4U2hMckwzUUtNQ1FuZVhkT0VjaEdqSW9zRG5Zekd5RTBpSzJGbWNvWHVSQU1QOHgKWDFreUlkazdENDFxSjQ5WlM1OEdBbXlLCi0tLS0tRU5EIFBSSVZBVEUgS0VZLS0tLS0K"
|
||||
tlscaName = "ca.crt"
|
||||
)
|
||||
|
||||
type MockQueue struct {
|
||||
cache_client.Store
|
||||
Synced bool
|
||||
}
|
||||
|
||||
func (f *MockQueue) HasSynced() bool {
|
||||
return f.Synced
|
||||
}
|
||||
|
||||
func (f *MockQueue) AddIfNotPresent(obj interface{}) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (f *MockQueue) Pop(process cache_client.PopProcessFunc) (interface{}, error) {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func (f *MockQueue) Close() {
|
||||
// just mock
|
||||
}
|
||||
|
||||
func buildSimpleClientSetForBackendSSL() *testclient.Clientset {
|
||||
return testclient.NewSimpleClientset()
|
||||
}
|
||||
|
||||
func buildIngListenerForBackendSSL() store.IngressLister {
|
||||
ingLister := store.IngressLister{}
|
||||
ingLister.Store = cache_client.NewStore(cache_client.DeletionHandlingMetaNamespaceKeyFunc)
|
||||
return ingLister
|
||||
}
|
||||
|
||||
func buildSecretForBackendSSL() *apiv1.Secret {
|
||||
return &apiv1.Secret{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "foo_secret",
|
||||
Namespace: metav1.NamespaceDefault,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func buildSecrListerForBackendSSL() store.SecretLister {
|
||||
secrLister := store.SecretLister{}
|
||||
secrLister.Store = cache_client.NewStore(cache_client.DeletionHandlingMetaNamespaceKeyFunc)
|
||||
|
||||
return secrLister
|
||||
}
|
||||
|
||||
/*
|
||||
func buildListers() *ingress.StoreLister {
|
||||
sl := &ingress.StoreLister{}
|
||||
sl.Ingress.Store = buildIngListenerForBackendSSL()
|
||||
sl.Secret.Store = buildSecrListerForBackendSSL()
|
||||
return sl
|
||||
}
|
||||
*/
|
||||
func buildControllerForBackendSSL() cache_client.Controller {
|
||||
cfg := &cache_client.Config{
|
||||
Queue: &MockQueue{Synced: true},
|
||||
}
|
||||
|
||||
return cache_client.New(cfg)
|
||||
}
|
||||
|
||||
/*
|
||||
func buildGenericControllerForBackendSSL() *NGINXController {
|
||||
gc := &NGINXController{
|
||||
syncRateLimiter: flowcontrol.NewTokenBucketRateLimiter(0.3, 1),
|
||||
cfg: &Configuration{
|
||||
Client: buildSimpleClientSetForBackendSSL(),
|
||||
},
|
||||
listers: buildListers(),
|
||||
}
|
||||
|
||||
gc.syncQueue = task.NewTaskQueue(gc.syncIngress)
|
||||
return gc
|
||||
}
|
||||
*/
|
||||
|
||||
func buildCrtKeyAndCA() ([]byte, []byte, []byte, error) {
|
||||
// prepare
|
||||
td, err := ioutil.TempDir("", "ssl")
|
||||
if err != nil {
|
||||
return nil, nil, nil, fmt.Errorf("error occurs while creating temp directory: %v", err)
|
||||
}
|
||||
ingress.DefaultSSLDirectory = td
|
||||
|
||||
dCrt, err := base64.StdEncoding.DecodeString(tlsCrt)
|
||||
if err != nil {
|
||||
return nil, nil, nil, err
|
||||
}
|
||||
|
||||
dKey, err := base64.StdEncoding.DecodeString(tlsKey)
|
||||
if err != nil {
|
||||
return nil, nil, nil, err
|
||||
}
|
||||
|
||||
dCa := dCrt
|
||||
|
||||
return dCrt, dKey, dCa, nil
|
||||
}
|
||||
|
||||
/*
|
||||
func TestSyncSecret(t *testing.T) {
|
||||
// prepare for test
|
||||
dCrt, dKey, dCa, err := buildCrtKeyAndCA()
|
||||
if err != nil {
|
||||
t.Fatalf("Unexpected error: %v", err)
|
||||
}
|
||||
|
||||
foos := []struct {
|
||||
tn string
|
||||
secretName string
|
||||
Data map[string][]byte
|
||||
expectSuccess bool
|
||||
}{
|
||||
{"getPemCertificate_error", "default/foo_secret", map[string][]byte{apiv1.TLSPrivateKeyKey: dKey}, false},
|
||||
{"normal_test", "default/foo_secret", map[string][]byte{apiv1.TLSCertKey: dCrt, apiv1.TLSPrivateKeyKey: dKey, tlscaName: dCa}, true},
|
||||
}
|
||||
|
||||
for _, foo := range foos {
|
||||
t.Run(foo.tn, func(t *testing.T) {
|
||||
ic := buildGenericControllerForBackendSSL()
|
||||
|
||||
// init secret for getPemCertificate
|
||||
secret := buildSecretForBackendSSL()
|
||||
secret.SetNamespace("default")
|
||||
secret.SetName("foo_secret")
|
||||
secret.Data = foo.Data
|
||||
ic.store..Secret.Add(secret)
|
||||
|
||||
key := "default/foo_secret"
|
||||
// for add
|
||||
ic.syncSecret(key)
|
||||
if foo.expectSuccess {
|
||||
// validate
|
||||
_, exist := ic.sslCertTracker.Get(key)
|
||||
if !exist {
|
||||
t.Errorf("Failed to sync secret: %s", foo.secretName)
|
||||
} else {
|
||||
// for update
|
||||
ic.syncSecret(key)
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetPemCertificate(t *testing.T) {
|
||||
// prepare
|
||||
dCrt, dKey, dCa, err := buildCrtKeyAndCA()
|
||||
if err != nil {
|
||||
t.Fatalf("Unexpected error: %v", err)
|
||||
}
|
||||
|
||||
foos := []struct {
|
||||
tn string
|
||||
secretName string
|
||||
Data map[string][]byte
|
||||
eErr bool
|
||||
}{
|
||||
{"sceret_not_exist", "default/foo_secret_not_exist", nil, true},
|
||||
{"data_not_complete_all_not_exist", "default/foo_secret", map[string][]byte{}, true},
|
||||
{"data_not_complete_TLSCertKey_not_exist", "default/foo_secret", map[string][]byte{apiv1.TLSPrivateKeyKey: dKey, tlscaName: dCa}, false},
|
||||
{"data_not_complete_TLSCertKeyAndCA_not_exist", "default/foo_secret", map[string][]byte{apiv1.TLSPrivateKeyKey: dKey}, true},
|
||||
{"data_not_complete_TLSPrivateKeyKey_not_exist", "default/foo_secret", map[string][]byte{apiv1.TLSCertKey: dCrt, tlscaName: dCa}, false},
|
||||
{"data_not_complete_TLSPrivateKeyKeyAndCA_not_exist", "default/foo_secret", map[string][]byte{apiv1.TLSCertKey: dCrt}, true},
|
||||
{"data_not_complete_CA_not_exist", "default/foo_secret", map[string][]byte{apiv1.TLSCertKey: dCrt, apiv1.TLSPrivateKeyKey: dKey}, false},
|
||||
{"normal_test", "default/foo_secret", map[string][]byte{apiv1.TLSCertKey: dCrt, apiv1.TLSPrivateKeyKey: dKey, tlscaName: dCa}, false},
|
||||
}
|
||||
|
||||
for _, foo := range foos {
|
||||
t.Run(foo.tn, func(t *testing.T) {
|
||||
ic := buildGenericControllerForBackendSSL()
|
||||
secret := buildSecretForBackendSSL()
|
||||
secret.Data = foo.Data
|
||||
ic.listers.Secret.Add(secret)
|
||||
sslCert, err := ic.getPemCertificate(foo.secretName)
|
||||
|
||||
if foo.eErr {
|
||||
if err == nil {
|
||||
t.Fatal("Expected error")
|
||||
}
|
||||
} else {
|
||||
if err != nil {
|
||||
t.Fatalf("Unexpected error: %v", err)
|
||||
}
|
||||
|
||||
if sslCert == nil {
|
||||
t.Error("Expected an ingress.SSLCert")
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
*/
|
|
@ -36,13 +36,9 @@ import (
|
|||
clientset "k8s.io/client-go/kubernetes"
|
||||
|
||||
"k8s.io/ingress-nginx/internal/ingress"
|
||||
"k8s.io/ingress-nginx/internal/ingress/annotations"
|
||||
"k8s.io/ingress-nginx/internal/ingress/annotations/healthcheck"
|
||||
"k8s.io/ingress-nginx/internal/ingress/annotations/parser"
|
||||
"k8s.io/ingress-nginx/internal/ingress/annotations/proxy"
|
||||
ngx_config "k8s.io/ingress-nginx/internal/ingress/controller/config"
|
||||
"k8s.io/ingress-nginx/internal/ingress/defaults"
|
||||
"k8s.io/ingress-nginx/internal/ingress/resolver"
|
||||
"k8s.io/ingress-nginx/internal/k8s"
|
||||
"k8s.io/ingress-nginx/internal/task"
|
||||
)
|
||||
|
@ -100,11 +96,6 @@ type Configuration struct {
|
|||
SyncRateLimit float32
|
||||
}
|
||||
|
||||
// GetDefaultBackend returns the default backend
|
||||
func (n NGINXController) GetDefaultBackend() defaults.Backend {
|
||||
return n.backendDefaults
|
||||
}
|
||||
|
||||
// GetPublishService returns the configured service used to set ingress status
|
||||
func (n NGINXController) GetPublishService() *apiv1.Service {
|
||||
s, err := n.store.GetService(n.cfg.PublishService)
|
||||
|
@ -115,16 +106,6 @@ func (n NGINXController) GetPublishService() *apiv1.Service {
|
|||
return s
|
||||
}
|
||||
|
||||
// GetSecret searches for a secret in the local secrets Store
|
||||
func (n NGINXController) GetSecret(name string) (*apiv1.Secret, error) {
|
||||
return n.store.GetSecret(name)
|
||||
}
|
||||
|
||||
// GetService searches for a service in the local secrets Store
|
||||
func (n NGINXController) GetService(name string) (*apiv1.Service, error) {
|
||||
return n.store.GetService(name)
|
||||
}
|
||||
|
||||
// sync collects all the pieces required to assemble the configuration file and
|
||||
// then sends the content to the backend (OnUpdate) receiving the populated
|
||||
// template as response reloading the backend if is required.
|
||||
|
@ -138,7 +119,7 @@ func (n *NGINXController) syncIngress(item interface{}) error {
|
|||
if element, ok := item.(task.Element); ok {
|
||||
if name, ok := element.Key.(string); ok {
|
||||
if ing, err := n.store.GetIngress(name); err == nil {
|
||||
n.readSecrets(ing)
|
||||
n.store.ReadSecrets(ing)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -368,7 +349,6 @@ func (n *NGINXController) getBackendServers(ingresses []*extensions.Ingress) ([]
|
|||
anns, err := n.store.GetIngressAnnotations(ing)
|
||||
if err != nil {
|
||||
glog.Errorf("unexpected error reading ingress annotations: %v", err)
|
||||
anns = &annotations.Ingress{}
|
||||
}
|
||||
|
||||
for _, rule := range ing.Spec.Rules {
|
||||
|
@ -580,29 +560,6 @@ func (n *NGINXController) getBackendServers(ingresses []*extensions.Ingress) ([]
|
|||
return aUpstreams, aServers
|
||||
}
|
||||
|
||||
// GetAuthCertificate is used by the auth-tls annotations to get a cert from a secret
|
||||
func (n NGINXController) GetAuthCertificate(name string) (*resolver.AuthSSLCert, error) {
|
||||
if _, exists := n.sslCertTracker.Get(name); !exists {
|
||||
n.syncSecret(name)
|
||||
}
|
||||
|
||||
_, err := n.store.GetSecret(name)
|
||||
if err != nil {
|
||||
return &resolver.AuthSSLCert{}, fmt.Errorf("unexpected error: %v", err)
|
||||
}
|
||||
|
||||
bc, exists := n.sslCertTracker.Get(name)
|
||||
if !exists {
|
||||
return &resolver.AuthSSLCert{}, fmt.Errorf("secret %v does not exist", name)
|
||||
}
|
||||
cert := bc.(*ingress.SSLCert)
|
||||
return &resolver.AuthSSLCert{
|
||||
Secret: name,
|
||||
CAFileName: cert.CAFileName,
|
||||
PemSHA: cert.PemSHA,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// createUpstreams creates the NGINX upstreams for each service referenced in
|
||||
// Ingress rules. The servers inside the upstream are endpoints.
|
||||
func (n *NGINXController) createUpstreams(data []*extensions.Ingress, du *ingress.Backend) map[string]*ingress.Backend {
|
||||
|
@ -610,7 +567,10 @@ func (n *NGINXController) createUpstreams(data []*extensions.Ingress, du *ingres
|
|||
upstreams[defUpstreamName] = du
|
||||
|
||||
for _, ing := range data {
|
||||
anns := n.getIngressAnnotations(ing)
|
||||
anns, err := n.store.GetIngressAnnotations(ing)
|
||||
if err != nil {
|
||||
glog.Errorf("unexpected error reading ingress annotations: %v", err)
|
||||
}
|
||||
|
||||
var defBackend string
|
||||
if ing.Spec.Backend != nil {
|
||||
|
@ -840,7 +800,7 @@ func (n *NGINXController) createServers(data []*extensions.Ingress,
|
|||
// remove the alias to avoid conflicts.
|
||||
aliases := make(map[string]string, len(data))
|
||||
|
||||
bdef := n.GetDefaultBackend()
|
||||
bdef := n.store.GetDefaultBackend()
|
||||
ngxProxy := proxy.Config{
|
||||
BodySize: bdef.ProxyBodySize,
|
||||
ConnectTimeout: bdef.ProxyConnectTimeout,
|
||||
|
@ -860,7 +820,7 @@ func (n *NGINXController) createServers(data []*extensions.Ingress,
|
|||
|
||||
// Tries to fetch the default Certificate from nginx configuration.
|
||||
// If it does not exists, use the ones generated on Start()
|
||||
defaultCertificate, err := n.getPemCertificate(n.cfg.DefaultSSLCertificate)
|
||||
defaultCertificate, err := n.store.GetLocalSecret(n.cfg.DefaultSSLCertificate)
|
||||
if err == nil {
|
||||
defaultPemFileName = defaultCertificate.PemFileName
|
||||
defaultPemSHA = defaultCertificate.PemSHA
|
||||
|
@ -883,7 +843,10 @@ func (n *NGINXController) createServers(data []*extensions.Ingress,
|
|||
|
||||
// initialize all the servers
|
||||
for _, ing := range data {
|
||||
anns := n.getIngressAnnotations(ing)
|
||||
anns, err := n.store.GetIngressAnnotations(ing)
|
||||
if err != nil {
|
||||
glog.Errorf("unexpected error reading ingress annotations: %v", err)
|
||||
}
|
||||
|
||||
// default upstream server
|
||||
un := du.Name
|
||||
|
@ -951,7 +914,10 @@ func (n *NGINXController) createServers(data []*extensions.Ingress,
|
|||
|
||||
// configure default location, alias, and SSL
|
||||
for _, ing := range data {
|
||||
anns := n.getIngressAnnotations(ing)
|
||||
anns, err := n.store.GetIngressAnnotations(ing)
|
||||
if err != nil {
|
||||
glog.Errorf("unexpected error reading ingress annotations: %v", err)
|
||||
}
|
||||
|
||||
for _, rule := range ing.Spec.Rules {
|
||||
host := rule.Host
|
||||
|
@ -1016,13 +982,12 @@ func (n *NGINXController) createServers(data []*extensions.Ingress,
|
|||
}
|
||||
|
||||
key := fmt.Sprintf("%v/%v", ing.Namespace, tlsSecretName)
|
||||
bc, exists := n.sslCertTracker.Get(key)
|
||||
if !exists {
|
||||
cert, err := n.store.GetLocalSecret(key)
|
||||
if err != nil {
|
||||
glog.Warningf("ssl certificate \"%v\" does not exist in local store", key)
|
||||
continue
|
||||
}
|
||||
|
||||
cert := bc.(*ingress.SSLCert)
|
||||
err = cert.Certificate.VerifyHostname(host)
|
||||
if err != nil {
|
||||
glog.Warningf("unexpected error validating SSL certificate %v for host %v. Reason: %v", key, host, err)
|
||||
|
@ -1148,24 +1113,6 @@ func (n *NGINXController) getEndpoints(
|
|||
return upsServers
|
||||
}
|
||||
|
||||
// readSecrets extracts information about secrets from an Ingress rule
|
||||
func (n *NGINXController) readSecrets(ing *extensions.Ingress) {
|
||||
for _, tls := range ing.Spec.TLS {
|
||||
if tls.SecretName == "" {
|
||||
continue
|
||||
}
|
||||
|
||||
key := fmt.Sprintf("%v/%v", ing.Namespace, tls.SecretName)
|
||||
n.syncSecret(key)
|
||||
}
|
||||
|
||||
key, _ := parser.GetStringAnnotation("auth-tls-secret", ing)
|
||||
if key == "" {
|
||||
return
|
||||
}
|
||||
n.syncSecret(key)
|
||||
}
|
||||
|
||||
func (n *NGINXController) isForceReload() bool {
|
||||
return atomic.LoadInt32(&n.forceReload) != 0
|
||||
}
|
||||
|
@ -1179,24 +1126,3 @@ func (n *NGINXController) SetForceReload(shouldReload bool) {
|
|||
atomic.StoreInt32(&n.forceReload, 0)
|
||||
}
|
||||
}
|
||||
|
||||
func (n *NGINXController) extractAnnotations(ing *extensions.Ingress) {
|
||||
glog.V(3).Infof("updating annotations information for ingress %v/%v", ing.Namespace, ing.Name)
|
||||
anns := n.annotations.Extract(ing)
|
||||
err := n.store.UpdateIngressAnnotation(anns)
|
||||
if err != nil {
|
||||
glog.Errorf("unexpected error updating annotations information for ingress %v/%v: %v", anns.Namespace, anns.Name, err)
|
||||
}
|
||||
}
|
||||
|
||||
// getByIngress returns the parsed annotations from an Ingress
|
||||
func (n *NGINXController) getIngressAnnotations(ing *extensions.Ingress) *annotations.Ingress {
|
||||
key := fmt.Sprintf("%v/%v", ing.Namespace, ing.Name)
|
||||
item, err := n.store.GetIngressAnnotations(ing)
|
||||
if err != nil {
|
||||
glog.Errorf("unexpected error getting ingress annotation %v: %v", key, err)
|
||||
return &annotations.Ingress{}
|
||||
}
|
||||
|
||||
return item
|
||||
}
|
||||
|
|
|
@ -18,7 +18,6 @@ package controller
|
|||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/base64"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
|
@ -35,7 +34,6 @@ import (
|
|||
|
||||
apiv1 "k8s.io/api/core/v1"
|
||||
extensions "k8s.io/api/extensions/v1beta1"
|
||||
"k8s.io/apimachinery/pkg/util/wait"
|
||||
"k8s.io/client-go/kubernetes/scheme"
|
||||
v1core "k8s.io/client-go/kubernetes/typed/core/v1"
|
||||
"k8s.io/client-go/tools/record"
|
||||
|
@ -50,7 +48,6 @@ import (
|
|||
"k8s.io/ingress-nginx/internal/ingress/controller/process"
|
||||
"k8s.io/ingress-nginx/internal/ingress/controller/store"
|
||||
ngx_template "k8s.io/ingress-nginx/internal/ingress/controller/template"
|
||||
"k8s.io/ingress-nginx/internal/ingress/defaults"
|
||||
"k8s.io/ingress-nginx/internal/ingress/status"
|
||||
ing_net "k8s.io/ingress-nginx/internal/net"
|
||||
"k8s.io/ingress-nginx/internal/net/dns"
|
||||
|
@ -95,16 +92,12 @@ func NewNGINXController(config *Configuration, fs file.Filesystem) *NGINXControl
|
|||
}
|
||||
|
||||
n := &NGINXController{
|
||||
backendDefaults: ngx_config.NewDefault().Backend,
|
||||
binary: ngx,
|
||||
|
||||
configmap: &apiv1.ConfigMap{},
|
||||
binary: ngx,
|
||||
|
||||
isIPV6Enabled: ing_net.IsIPv6Enabled(),
|
||||
|
||||
resolver: h,
|
||||
cfg: config,
|
||||
sslCertTracker: store.NewSSLCertTracker(),
|
||||
syncRateLimiter: flowcontrol.NewTokenBucketRateLimiter(config.SyncRateLimit, 1),
|
||||
|
||||
recorder: eventBroadcaster.NewRecorder(scheme.Scheme, apiv1.EventSource{
|
||||
|
@ -112,7 +105,7 @@ func NewNGINXController(config *Configuration, fs file.Filesystem) *NGINXControl
|
|||
}),
|
||||
|
||||
stopCh: make(chan struct{}),
|
||||
updateCh: make(chan store.Event),
|
||||
updateCh: make(chan store.Event, 1024),
|
||||
|
||||
stopLock: &sync.Mutex{},
|
||||
|
||||
|
@ -136,7 +129,7 @@ func NewNGINXController(config *Configuration, fs file.Filesystem) *NGINXControl
|
|||
|
||||
n.syncQueue = task.NewTaskQueue(n.syncIngress)
|
||||
|
||||
n.annotations = annotations.NewAnnotationExtractor(n)
|
||||
n.annotations = annotations.NewAnnotationExtractor(n.store)
|
||||
|
||||
if config.UpdateStatus {
|
||||
n.syncStatus = status.NewStatusSyncer(status.Config{
|
||||
|
@ -203,10 +196,6 @@ type NGINXController struct {
|
|||
|
||||
syncStatus status.Sync
|
||||
|
||||
// local store of SSL certificates
|
||||
// (only certificates used in ingress)
|
||||
sslCertTracker *store.SSLCertTracker
|
||||
|
||||
syncRateLimiter flowcontrol.RateLimiter
|
||||
|
||||
// stopLock is used to enforce only a single call to Stop is active.
|
||||
|
@ -227,8 +216,6 @@ type NGINXController struct {
|
|||
|
||||
t *ngx_template.Template
|
||||
|
||||
configmap *apiv1.ConfigMap
|
||||
|
||||
binary string
|
||||
resolver []net.IP
|
||||
|
||||
|
@ -238,15 +225,8 @@ type NGINXController struct {
|
|||
// returns true if IPV6 is enabled in the pod
|
||||
isIPV6Enabled bool
|
||||
|
||||
// returns true if proxy protocol es enabled
|
||||
IsProxyProtocolEnabled bool
|
||||
|
||||
isShuttingDown bool
|
||||
|
||||
Proxy *TCPProxy
|
||||
|
||||
backendDefaults defaults.Backend
|
||||
|
||||
store store.Storer
|
||||
|
||||
fileSystem filesystem.Filesystem
|
||||
|
@ -258,28 +238,10 @@ func (n *NGINXController) Start() {
|
|||
|
||||
n.store.Run(n.stopCh)
|
||||
|
||||
// initial sync of secrets to avoid unnecessary reloads
|
||||
glog.Info("running initial sync of secrets")
|
||||
for _, ing := range n.store.ListIngresses() {
|
||||
if !class.IsValid(ing) {
|
||||
a := ing.GetAnnotations()[class.IngressKey]
|
||||
glog.Infof("ignoring add for ingress %v based on annotation %v with value %v", ing.Name, class.IngressKey, a)
|
||||
continue
|
||||
}
|
||||
|
||||
n.readSecrets(ing)
|
||||
}
|
||||
|
||||
if n.cfg.EnableSSLChainCompletion {
|
||||
go wait.Until(n.checkSSLChainIssues, 60*time.Second, n.stopCh)
|
||||
}
|
||||
|
||||
if n.syncStatus != nil {
|
||||
go n.syncStatus.Run()
|
||||
}
|
||||
|
||||
go wait.Until(n.checkMissingSecrets, 30*time.Second, n.stopCh)
|
||||
|
||||
done := make(chan error, 1)
|
||||
cmd := exec.Command(n.binary, "-c", cfgPath)
|
||||
|
||||
|
@ -293,21 +255,6 @@ func (n *NGINXController) Start() {
|
|||
glog.Info("starting NGINX process...")
|
||||
n.start(cmd)
|
||||
|
||||
go func() {
|
||||
for {
|
||||
select {
|
||||
case evt := <-n.updateCh:
|
||||
if n.isShuttingDown {
|
||||
break
|
||||
}
|
||||
glog.Infof("Event %v received - object %v", evt.Type, evt.Obj)
|
||||
n.syncQueue.Enqueue(evt.Obj)
|
||||
case <-n.stopCh:
|
||||
break
|
||||
}
|
||||
}
|
||||
}()
|
||||
|
||||
go n.syncQueue.Run(time.Second, n.stopCh)
|
||||
// force initial sync
|
||||
n.syncQueue.Enqueue(&extensions.Ingress{})
|
||||
|
@ -332,6 +279,12 @@ func (n *NGINXController) Start() {
|
|||
// start a new nginx master process if the controller is not being stopped
|
||||
n.start(cmd)
|
||||
}
|
||||
case evt := <-n.updateCh:
|
||||
if n.isShuttingDown {
|
||||
break
|
||||
}
|
||||
glog.V(3).Infof("Event %v received - object %v", evt.Type, evt.Obj)
|
||||
n.syncQueue.Enqueue(evt.Obj)
|
||||
case <-n.stopCh:
|
||||
break
|
||||
}
|
||||
|
@ -434,37 +387,6 @@ Error: %v
|
|||
return nil
|
||||
}
|
||||
|
||||
// SetConfig sets the configured configmap
|
||||
func (n *NGINXController) SetConfig(cmap *apiv1.ConfigMap) {
|
||||
n.configmap = cmap
|
||||
n.IsProxyProtocolEnabled = false
|
||||
|
||||
m := map[string]string{}
|
||||
if cmap != nil {
|
||||
m = cmap.Data
|
||||
}
|
||||
|
||||
val, ok := m["use-proxy-protocol"]
|
||||
if ok {
|
||||
b, err := strconv.ParseBool(val)
|
||||
if err == nil {
|
||||
n.IsProxyProtocolEnabled = b
|
||||
}
|
||||
}
|
||||
|
||||
c := ngx_template.ReadConfig(m)
|
||||
if c.SSLSessionTicketKey != "" {
|
||||
d, err := base64.StdEncoding.DecodeString(c.SSLSessionTicketKey)
|
||||
if err != nil {
|
||||
glog.Warningf("unexpected error decoding key ssl-session-ticket-key: %v", err)
|
||||
c.SSLSessionTicketKey = ""
|
||||
}
|
||||
ioutil.WriteFile("/etc/nginx/tickets.key", d, 0644)
|
||||
}
|
||||
|
||||
n.backendDefaults = c.Backend
|
||||
}
|
||||
|
||||
// OnUpdate is called periodically by syncQueue to keep the configuration in sync.
|
||||
//
|
||||
// 1. converts configmap configuration to custom configuration object
|
||||
|
@ -474,45 +396,43 @@ func (n *NGINXController) SetConfig(cmap *apiv1.ConfigMap) {
|
|||
// returning nill implies the backend will be reloaded.
|
||||
// if an error is returned means requeue the update
|
||||
func (n *NGINXController) OnUpdate(ingressCfg ingress.Configuration) error {
|
||||
cfg := ngx_template.ReadConfig(n.configmap.Data)
|
||||
cfg := n.store.GetBackendConfiguration()
|
||||
cfg.Resolver = n.resolver
|
||||
|
||||
servers := []*TCPServer{}
|
||||
for _, pb := range ingressCfg.PassthroughBackends {
|
||||
svc := pb.Service
|
||||
if svc == nil {
|
||||
glog.Warningf("missing service for PassthroughBackends %v", pb.Backend)
|
||||
continue
|
||||
}
|
||||
port, err := strconv.Atoi(pb.Port.String())
|
||||
if err != nil {
|
||||
for _, sp := range svc.Spec.Ports {
|
||||
if sp.Name == pb.Port.String() {
|
||||
port = int(sp.Port)
|
||||
break
|
||||
}
|
||||
}
|
||||
} else {
|
||||
for _, sp := range svc.Spec.Ports {
|
||||
if sp.Port == int32(port) {
|
||||
port = int(sp.Port)
|
||||
break
|
||||
/*
|
||||
servers := []*TCPServer{}
|
||||
for _, pb := range ingressCfg.PassthroughBackends {
|
||||
svc := pb.Service
|
||||
if svc == nil {
|
||||
glog.Warningf("missing service for PassthroughBackends %v", pb.Backend)
|
||||
continue
|
||||
}
|
||||
port, err := strconv.Atoi(pb.Port.String())
|
||||
if err != nil {
|
||||
for _, sp := range svc.Spec.Ports {
|
||||
if sp.Name == pb.Port.String() {
|
||||
port = int(sp.Port)
|
||||
break
|
||||
}
|
||||
}
|
||||
} else {
|
||||
for _, sp := range svc.Spec.Ports {
|
||||
if sp.Port == int32(port) {
|
||||
port = int(sp.Port)
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//TODO: Allow PassthroughBackends to specify they support proxy-protocol
|
||||
servers = append(servers, &TCPServer{
|
||||
Hostname: pb.Hostname,
|
||||
IP: svc.Spec.ClusterIP,
|
||||
Port: port,
|
||||
ProxyProtocol: false,
|
||||
})
|
||||
}
|
||||
|
||||
//TODO: Allow PassthroughBackends to specify they support proxy-protocol
|
||||
servers = append(servers, &TCPServer{
|
||||
Hostname: pb.Hostname,
|
||||
IP: svc.Spec.ClusterIP,
|
||||
Port: port,
|
||||
ProxyProtocol: false,
|
||||
})
|
||||
}
|
||||
|
||||
if n.cfg.EnableSSLPassthrough {
|
||||
n.Proxy.ServerList = servers
|
||||
}
|
||||
*/
|
||||
|
||||
// we need to check if the status module configuration changed
|
||||
if cfg.EnableVtsStatus {
|
||||
|
|
|
@ -201,8 +201,8 @@ func (s k8sStore) checkMissingSecrets() {
|
|||
}
|
||||
}
|
||||
|
||||
// readSecrets extracts information about secrets from an Ingress rule
|
||||
func (s k8sStore) readSecrets(ing *extensions.Ingress) {
|
||||
// ReadSecrets extracts information about secrets from an Ingress rule
|
||||
func (s k8sStore) ReadSecrets(ing *extensions.Ingress) {
|
||||
for _, tls := range ing.Spec.TLS {
|
||||
if tls.SecretName == "" {
|
||||
continue
|
||||
|
|
|
@ -17,7 +17,9 @@ limitations under the License.
|
|||
package store
|
||||
|
||||
import (
|
||||
"encoding/base64"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"reflect"
|
||||
"time"
|
||||
|
||||
|
@ -41,6 +43,8 @@ import (
|
|||
"k8s.io/ingress-nginx/internal/ingress/annotations"
|
||||
"k8s.io/ingress-nginx/internal/ingress/annotations/class"
|
||||
"k8s.io/ingress-nginx/internal/ingress/annotations/parser"
|
||||
ngx_config "k8s.io/ingress-nginx/internal/ingress/controller/config"
|
||||
ngx_template "k8s.io/ingress-nginx/internal/ingress/controller/template"
|
||||
"k8s.io/ingress-nginx/internal/ingress/defaults"
|
||||
"k8s.io/ingress-nginx/internal/ingress/resolver"
|
||||
"k8s.io/ingress-nginx/internal/k8s"
|
||||
|
@ -49,6 +53,9 @@ import (
|
|||
// Storer is the interface that wraps the required methods to gather information
|
||||
// about ingresses, services, secrets and ingress annotations.
|
||||
type Storer interface {
|
||||
// GetBackendConfiguration returns the nginx configuration stored in a configmap
|
||||
GetBackendConfiguration() ngx_config.Configuration
|
||||
|
||||
// GetConfigMap returns a ConfigmMap using the namespace and name as key
|
||||
GetConfigMap(key string) (*apiv1.ConfigMap, error)
|
||||
|
||||
|
@ -69,9 +76,6 @@ type Storer interface {
|
|||
// GetIngressAnnotations returns the annotations associated to an Ingress
|
||||
GetIngressAnnotations(ing *extensions.Ingress) (*annotations.Ingress, error)
|
||||
|
||||
// UpdateIngressAnnotation updates the annotations associated to an Ingress
|
||||
UpdateIngressAnnotation(ing *annotations.Ingress) error
|
||||
|
||||
// GetLocalSecret returns the local copy of a Secret
|
||||
GetLocalSecret(name string) (*ingress.SSLCert, error)
|
||||
|
||||
|
@ -86,11 +90,11 @@ type Storer interface {
|
|||
// GetDefaultBackend returns the default backend configuration
|
||||
GetDefaultBackend() defaults.Backend
|
||||
|
||||
// SetDefaultBackend sets the default backend configuration
|
||||
SetDefaultBackend(defaults.Backend)
|
||||
|
||||
// Run initiates the synchronization of the controllers
|
||||
Run(stopCh chan struct{})
|
||||
|
||||
// ReadSecrets extracts information about secrets from an Ingress rule
|
||||
ReadSecrets(*extensions.Ingress)
|
||||
}
|
||||
|
||||
// EventType type of event associated with an informer
|
||||
|
@ -162,7 +166,7 @@ func (c *Controller) Run(stopCh chan struct{}) {
|
|||
type k8sStore struct {
|
||||
isOCSPCheckEnabled bool
|
||||
|
||||
backendDefaults defaults.Backend
|
||||
backendConfig ngx_config.Configuration
|
||||
|
||||
cache *Controller
|
||||
// listers
|
||||
|
@ -195,6 +199,7 @@ func New(checkOCSP bool,
|
|||
sslStore: NewSSLCertTracker(),
|
||||
filesystem: fs,
|
||||
updateCh: updateCh,
|
||||
backendConfig: ngx_config.NewDefault(),
|
||||
}
|
||||
|
||||
eventBroadcaster := record.NewBroadcaster()
|
||||
|
@ -337,10 +342,11 @@ func New(checkOCSP bool,
|
|||
|
||||
mapEventHandler := cache.ResourceEventHandlerFuncs{
|
||||
AddFunc: func(obj interface{}) {
|
||||
upCmap := obj.(*apiv1.ConfigMap)
|
||||
mapKey := fmt.Sprintf("%s/%s", upCmap.Namespace, upCmap.Name)
|
||||
m := obj.(*apiv1.ConfigMap)
|
||||
mapKey := fmt.Sprintf("%s/%s", m.Namespace, m.Name)
|
||||
if mapKey == configmap {
|
||||
glog.V(2).Infof("adding configmap %v to backend", mapKey)
|
||||
store.setConfig(m)
|
||||
updateCh <- Event{
|
||||
Type: CreateEvent,
|
||||
Obj: obj,
|
||||
|
@ -349,10 +355,11 @@ func New(checkOCSP bool,
|
|||
},
|
||||
UpdateFunc: func(old, cur interface{}) {
|
||||
if !reflect.DeepEqual(old, cur) {
|
||||
upCmap := cur.(*apiv1.ConfigMap)
|
||||
mapKey := fmt.Sprintf("%s/%s", upCmap.Namespace, upCmap.Name)
|
||||
m := cur.(*apiv1.ConfigMap)
|
||||
mapKey := fmt.Sprintf("%s/%s", m.Namespace, m.Name)
|
||||
if mapKey == configmap {
|
||||
glog.V(2).Infof("updating configmap backend (%v)", mapKey)
|
||||
store.setConfig(m)
|
||||
updateCh <- Event{
|
||||
Type: UpdateEvent,
|
||||
Obj: cur,
|
||||
|
@ -360,7 +367,7 @@ func New(checkOCSP bool,
|
|||
}
|
||||
// updates to configuration configmaps can trigger an update
|
||||
if mapKey == configmap || mapKey == tcp || mapKey == udp {
|
||||
recorder.Eventf(upCmap, apiv1.EventTypeNormal, "UPDATE", fmt.Sprintf("ConfigMap %v", mapKey))
|
||||
recorder.Eventf(m, apiv1.EventTypeNormal, "UPDATE", fmt.Sprintf("ConfigMap %v", mapKey))
|
||||
updateCh <- Event{
|
||||
Type: UpdateEvent,
|
||||
Obj: cur,
|
||||
|
@ -452,20 +459,14 @@ func (s k8sStore) GetIngressAnnotations(ing *extensions.Ingress) (*annotations.I
|
|||
key := fmt.Sprintf("%v/%v", ing.Namespace, ing.Name)
|
||||
item, exists, err := s.listers.IngressAnnotation.GetByKey(key)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("unexpected error getting ingress annotation %v: %v", key, err)
|
||||
return &annotations.Ingress{}, fmt.Errorf("unexpected error getting ingress annotation %v: %v", key, err)
|
||||
}
|
||||
if !exists {
|
||||
return nil, fmt.Errorf("ingress annotation %v was not found", key)
|
||||
return &annotations.Ingress{}, fmt.Errorf("ingress annotations %v was not found", key)
|
||||
}
|
||||
return item.(*annotations.Ingress), nil
|
||||
}
|
||||
|
||||
// UpdateIngressAnnotation updates the annotations associated to an Ingress
|
||||
func (s k8sStore) UpdateIngressAnnotation(ing *annotations.Ingress) error {
|
||||
key := fmt.Sprintf("%v/%v", ing.Namespace, ing.Name)
|
||||
return s.listers.IngressAnnotation.Update(key)
|
||||
}
|
||||
|
||||
// GetLocalSecret returns the local copy of a Secret
|
||||
func (s k8sStore) GetLocalSecret(key string) (*ingress.SSLCert, error) {
|
||||
return s.sslStore.ByKey(key)
|
||||
|
@ -499,11 +500,25 @@ func (s k8sStore) GetAuthCertificate(name string) (*resolver.AuthSSLCert, error)
|
|||
|
||||
// GetDefaultBackend returns the default backend
|
||||
func (s k8sStore) GetDefaultBackend() defaults.Backend {
|
||||
return s.backendDefaults
|
||||
return s.backendConfig.Backend
|
||||
}
|
||||
|
||||
func (s *k8sStore) SetDefaultBackend(bd defaults.Backend) {
|
||||
s.backendDefaults = bd
|
||||
func (s k8sStore) GetBackendConfiguration() ngx_config.Configuration {
|
||||
return s.backendConfig
|
||||
}
|
||||
|
||||
func (s *k8sStore) setConfig(cmap *apiv1.ConfigMap) {
|
||||
s.backendConfig = ngx_template.ReadConfig(cmap.Data)
|
||||
|
||||
// TODO: this should not be done here
|
||||
if s.backendConfig.SSLSessionTicketKey != "" {
|
||||
d, err := base64.StdEncoding.DecodeString(s.backendConfig.SSLSessionTicketKey)
|
||||
if err != nil {
|
||||
glog.Warningf("unexpected error decoding key ssl-session-ticket-key: %v", err)
|
||||
s.backendConfig.SSLSessionTicketKey = ""
|
||||
}
|
||||
ioutil.WriteFile("/etc/nginx/tickets.key", d, 0644)
|
||||
}
|
||||
}
|
||||
|
||||
// Run initiates the synchronization of the controllers
|
||||
|
@ -515,7 +530,7 @@ func (s k8sStore) Run(stopCh chan struct{}) {
|
|||
// initial sync of secrets to avoid unnecessary reloads
|
||||
glog.Info("running initial sync of secrets")
|
||||
for _, ing := range s.ListIngresses() {
|
||||
s.readSecrets(ing)
|
||||
s.ReadSecrets(ing)
|
||||
}
|
||||
|
||||
// start goroutine to check for missing local secrets
|
||||
|
|
|
@ -1,113 +0,0 @@
|
|||
/*
|
||||
Copyright 2015 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package store
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
apiv1 "k8s.io/api/core/v1"
|
||||
"k8s.io/client-go/tools/cache"
|
||||
)
|
||||
|
||||
// IngressLister makes a Store that lists Ingress.
|
||||
type IngressLister struct {
|
||||
cache.Store
|
||||
}
|
||||
|
||||
// IngressAnnotationsLister makes a Store that lists annotations in Ingress rules.
|
||||
type IngressAnnotationsLister struct {
|
||||
cache.Store
|
||||
}
|
||||
|
||||
// SecretLister makes a Store that lists Secrets.
|
||||
type SecretLister struct {
|
||||
cache.Store
|
||||
}
|
||||
|
||||
// GetByName searches for a secret in the local secrets Store
|
||||
func (sl *SecretLister) GetByName(name string) (*apiv1.Secret, error) {
|
||||
s, exists, err := sl.GetByKey(name)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if !exists {
|
||||
return nil, fmt.Errorf("secret %v was not found", name)
|
||||
}
|
||||
return s.(*apiv1.Secret), nil
|
||||
}
|
||||
|
||||
// ConfigMapLister makes a Store that lists Configmaps.
|
||||
type ConfigMapLister struct {
|
||||
cache.Store
|
||||
}
|
||||
|
||||
// GetByName searches for a configmap in the local configmaps Store
|
||||
func (cml *ConfigMapLister) GetByName(name string) (*apiv1.ConfigMap, error) {
|
||||
s, exists, err := cml.GetByKey(name)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if !exists {
|
||||
return nil, fmt.Errorf("configmap %v was not found", name)
|
||||
}
|
||||
return s.(*apiv1.ConfigMap), nil
|
||||
}
|
||||
|
||||
// ServiceLister makes a Store that lists Services.
|
||||
type ServiceLister struct {
|
||||
cache.Store
|
||||
}
|
||||
|
||||
// GetByName searches for a service in the local secrets Store
|
||||
func (sl *ServiceLister) GetByName(name string) (*apiv1.Service, error) {
|
||||
s, exists, err := sl.GetByKey(name)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if !exists {
|
||||
return nil, fmt.Errorf("service %v was not found", name)
|
||||
}
|
||||
return s.(*apiv1.Service), nil
|
||||
}
|
||||
|
||||
// EndpointLister makes a Store that lists Endpoints.
|
||||
type EndpointLister struct {
|
||||
cache.Store
|
||||
}
|
||||
|
||||
// GetServiceEndpoints returns the endpoints of a service, matched on service name.
|
||||
func (s *EndpointLister) GetServiceEndpoints(svc *apiv1.Service) (*apiv1.Endpoints, error) {
|
||||
for _, m := range s.Store.List() {
|
||||
ep := m.(*apiv1.Endpoints)
|
||||
if svc.Name == ep.Name && svc.Namespace == ep.Namespace {
|
||||
return ep, nil
|
||||
}
|
||||
}
|
||||
return nil, fmt.Errorf("could not find endpoints for service: %v", svc.Name)
|
||||
}
|
||||
|
||||
// SSLCertTracker holds a store of referenced Secrets in Ingress rules
|
||||
type SSLCertTracker struct {
|
||||
cache.ThreadSafeStore
|
||||
}
|
||||
|
||||
// NewSSLCertTracker creates a new SSLCertTracker store
|
||||
func NewSSLCertTracker() *SSLCertTracker {
|
||||
return &SSLCertTracker{
|
||||
cache.NewThreadSafeStore(cache.Indexers{}, cache.Indices{}),
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue