Compare commits

...

12 Commits

Author SHA1 Message Date
vardhaman22
ad32b99079 fix listener call 2023-09-12 11:45:42 +05:30
vardhaman22
706df9c790 updated deps for k8s 1.27 2023-09-12 11:45:42 +05:30
renovate-rancher[bot]
3e7612c2c9 Update module github.com/sirupsen/logrus to v1.9.3 2023-08-15 12:43:48 -07:00
Derek Nola
e6585da47a Merge pull request #78 from knoppiks/multiple-ca-certs
Allow multiple (intermediate) CA certs
2023-08-11 12:43:10 -07:00
Jonas Wagner
6cc9a670e1 Prevent Panic for empty Arrays on Error
Co-authored-by: Brad Davidson <brad@oatmail.org>
Signed-off-by: Jonas Wagner <jwagner@knoppiks.de>
2023-07-14 08:28:48 +02:00
Jonas Wagner
8f13b193a1 Use more Verbose name for Listener
Co-authored-by: Brad Davidson <brad@oatmail.org>
Signed-off-by: Jonas Wagner <jwagner@knoppiks.de
2023-07-14 08:28:47 +02:00
Jonas Wagner
02304047cf Enable intermediate CA Certificates
Signed-off-by: Jonas Wagner <jwagner@knoppiks.de>
2023-07-10 09:42:17 +02:00
Kevin Joiner
4c1ac9bd4b Removes wait loop for listener certs. 2023-07-06 11:20:27 -07:00
Ricardo Weir
2b62d5cc69 Merge pull request #71 from rancher/deploy-renovate-2023-04-18-11-27-11
Add initial Renovate configuration
2023-04-27 10:28:43 -07:00
renovate-rancher[bot]
2ac221e5d6 Add initial Renovate configuration 2023-04-18 11:27:12 +00:00
Ricardo Weir
b7a028fe3f Merge pull request #69 from rmweir/update-wrangler
Update wrangler to v1.1.0
2023-02-22 14:08:10 -07:00
Ricardo Weir
a150115362 Update wrangler to v1.1.0 2023-02-21 15:41:43 -07:00
9 changed files with 522 additions and 509 deletions

9
.github/renovate.json vendored Normal file
View File

@@ -0,0 +1,9 @@
{
"extends": [
"github>rancher/renovate-config#release"
],
"baseBranches": [
"master"
],
"prHourlyLimit": 2
}

25
.github/workflows/renovate.yml vendored Normal file
View File

@@ -0,0 +1,25 @@
name: Renovate
on:
workflow_dispatch:
inputs:
logLevel:
description: "Override default log level"
required: false
default: "info"
type: string
overrideSchedule:
description: "Override all schedules"
required: false
default: "false"
type: string
# Run twice in the early morning (UTC) for initial and follow up steps (create pull request and merge)
schedule:
- cron: '30 4,6 * * *'
jobs:
call-workflow:
uses: rancher/renovate-config/.github/workflows/renovate.yml@release
with:
logLevel: ${{ inputs.logLevel || 'info' }}
overrideSchedule: ${{ github.event.inputs.overrideSchedule == 'true' && '{''schedule'':null}' || '' }}
secrets: inherit

View File

@@ -25,18 +25,28 @@ func GenCA() (*x509.Certificate, crypto.Signer, error) {
return caCert, caKey, nil
}
// Deprecated: Use LoadOrGenCAChain instead as it supports intermediate CAs
func LoadOrGenCA() (*x509.Certificate, crypto.Signer, error) {
cert, key, err := loadCA()
if err == nil {
return cert, key, nil
}
cert, key, err = GenCA()
chain, signer, err := LoadOrGenCAChain()
if err != nil {
return nil, nil, err
}
return chain[0], signer, err
}
certBytes, keyBytes, err := Marshal(cert, key)
func LoadOrGenCAChain() ([]*x509.Certificate, crypto.Signer, error) {
certs, key, err := loadCA()
if err == nil {
return certs, key, nil
}
cert, key, err := GenCA()
if err != nil {
return nil, nil, err
}
certs = []*x509.Certificate{cert}
certBytes, keyBytes, err := MarshalChain(key, certs...)
if err != nil {
return nil, nil, err
}
@@ -53,14 +63,22 @@ func LoadOrGenCA() (*x509.Certificate, crypto.Signer, error) {
return nil, nil, err
}
return cert, key, nil
return certs, key, nil
}
func loadCA() (*x509.Certificate, crypto.Signer, error) {
return LoadCerts("./certs/ca.pem", "./certs/ca.key")
func loadCA() ([]*x509.Certificate, crypto.Signer, error) {
return LoadCertsChain("./certs/ca.pem", "./certs/ca.key")
}
func LoadCA(caPem, caKey []byte) (*x509.Certificate, crypto.Signer, error) {
chain, signer, err := LoadCAChain(caPem, caKey)
if err != nil {
return nil, nil, err
}
return chain[0], signer, nil
}
func LoadCAChain(caPem, caKey []byte) ([]*x509.Certificate, crypto.Signer, error) {
key, err := cert.ParsePrivateKeyPEM(caKey)
if err != nil {
return nil, nil, err
@@ -70,15 +88,24 @@ func LoadCA(caPem, caKey []byte) (*x509.Certificate, crypto.Signer, error) {
return nil, nil, fmt.Errorf("key is not a crypto.Signer")
}
cert, err := ParseCertPEM(caPem)
certs, err := cert.ParseCertsPEM(caPem)
if err != nil {
return nil, nil, err
}
return cert, signer, nil
return certs, signer, nil
}
// Deprecated: Use LoadCertsChain instead as it supports intermediate CAs
func LoadCerts(certFile, keyFile string) (*x509.Certificate, crypto.Signer, error) {
chain, signer, err := LoadCertsChain(certFile, keyFile)
if err != nil {
return nil, nil, err
}
return chain[0], signer, err
}
func LoadCertsChain(certFile, keyFile string) ([]*x509.Certificate, crypto.Signer, error) {
caPem, err := ioutil.ReadFile(certFile)
if err != nil {
return nil, nil, err
@@ -88,5 +115,5 @@ func LoadCerts(certFile, keyFile string) (*x509.Certificate, crypto.Signer, erro
return nil, nil, err
}
return LoadCA(caPem, caKey)
return LoadCAChain(caPem, caKey)
}

View File

@@ -33,7 +33,7 @@ var (
)
type TLS struct {
CACert *x509.Certificate
CACert []*x509.Certificate
CAKey crypto.Signer
CN string
Organization []string
@@ -178,7 +178,7 @@ func (t *TLS) generateCert(secret *v1.Secret, cn ...string) (*v1.Secret, bool, e
return nil, false, err
}
keyBytes, certBytes, err := MarshalChain(privateKey, newCert, t.CACert)
keyBytes, certBytes, err := MarshalChain(privateKey, append([]*x509.Certificate{newCert}, t.CACert...)...)
if err != nil {
return nil, false, err
}
@@ -226,14 +226,16 @@ func (t *TLS) Verify(secret *v1.Secret) error {
x509.ExtKeyUsageAny,
},
}
verifyOpts.Roots.AddCert(t.CACert)
for _, c := range t.CACert {
verifyOpts.Roots.AddCert(c)
}
_, err = certificates[0].Verify(verifyOpts)
return err
}
func (t *TLS) newCert(domains []string, ips []net.IP, privateKey crypto.Signer) (*x509.Certificate, error) {
return NewSignedCert(privateKey, t.CACert, t.CAKey, t.CN, t.Organization, domains, ips)
return NewSignedCert(privateKey, t.CACert[0], t.CAKey, t.CN, t.Organization, domains, ips)
}
func populateCN(secret *v1.Secret, cn ...string) *v1.Secret {

70
go.mod
View File

@@ -1,51 +1,63 @@
module github.com/rancher/dynamiclistener
go 1.19
go 1.20
require (
github.com/rancher/wrangler v0.8.9
github.com/sirupsen/logrus v1.4.2
golang.org/x/crypto v0.0.0-20210322153248-0c34fe9e7dc2
k8s.io/api v0.18.8
k8s.io/apimachinery v0.18.8
k8s.io/client-go v0.18.8
github.com/rancher/wrangler v1.1.1-0.20230831050635-df1bd5aae9df
github.com/sirupsen/logrus v1.9.3
github.com/stretchr/testify v1.8.4
golang.org/x/crypto v0.11.0
k8s.io/api v0.27.4
k8s.io/apimachinery v0.27.4
k8s.io/client-go v0.27.4
)
require (
github.com/beorn7/perks v1.0.1 // indirect
github.com/cespare/xxhash/v2 v2.1.2 // indirect
github.com/davecgh/go-spew v1.1.1 // indirect
github.com/emicklei/go-restful/v3 v3.9.0 // indirect
github.com/evanphx/json-patch v4.12.0+incompatible // indirect
github.com/go-logr/logr v1.2.3 // indirect
github.com/go-openapi/jsonpointer v0.19.6 // indirect
github.com/go-openapi/jsonreference v0.20.1 // indirect
github.com/go-openapi/swag v0.22.3 // indirect
github.com/gogo/protobuf v1.3.2 // indirect
github.com/golang/protobuf v1.5.2 // indirect
github.com/golang/protobuf v1.5.3 // indirect
github.com/google/gnostic v0.5.7-v3refs // indirect
github.com/google/go-cmp v0.5.8 // indirect
github.com/google/go-cmp v0.5.9 // indirect
github.com/google/gofuzz v1.2.0 // indirect
github.com/googleapis/gnostic v0.3.1 // indirect
github.com/hashicorp/golang-lru v0.5.3 // indirect
github.com/google/uuid v1.3.0 // indirect
github.com/josharian/intern v1.0.0 // indirect
github.com/json-iterator/go v1.1.12 // indirect
github.com/konsorten/go-windows-terminal-sequences v1.0.3 // indirect
github.com/mailru/easyjson v0.7.7 // indirect
github.com/matttproud/golang_protobuf_extensions v1.0.2 // indirect
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
github.com/modern-go/reflect2 v1.0.2 // indirect
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect
github.com/pkg/errors v0.9.1 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect
github.com/rancher/lasso v0.0.0-20210616224652-fc3ebd901c08 // indirect
github.com/stretchr/testify v1.8.0 // indirect
golang.org/x/net v0.0.0-20221004154528-8021a29435af // indirect
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45 // indirect
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9 // indirect
golang.org/x/sys v0.0.0-20221010170243-090e33056c14 // indirect
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211 // indirect
golang.org/x/text v0.3.8 // indirect
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4 // indirect
google.golang.org/appengine v1.6.1 // indirect
google.golang.org/protobuf v1.27.1 // indirect
github.com/prometheus/client_golang v1.14.0 // indirect
github.com/prometheus/client_model v0.3.0 // indirect
github.com/prometheus/common v0.37.0 // indirect
github.com/prometheus/procfs v0.8.0 // indirect
github.com/rancher/lasso v0.0.0-20230830164424-d684fdeb6f29 // indirect
golang.org/x/net v0.12.0 // indirect
golang.org/x/oauth2 v0.10.0 // indirect
golang.org/x/sync v0.1.0 // indirect
golang.org/x/sys v0.10.0 // indirect
golang.org/x/term v0.10.0 // indirect
golang.org/x/text v0.11.0 // indirect
golang.org/x/time v0.3.0 // indirect
google.golang.org/appengine v1.6.7 // indirect
google.golang.org/protobuf v1.31.0 // indirect
gopkg.in/inf.v0 v0.9.1 // indirect
gopkg.in/yaml.v2 v2.4.0 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
k8s.io/klog v1.0.0 // indirect
k8s.io/klog/v2 v2.80.1 // indirect
k8s.io/kube-openapi v0.0.0-20220803162953-67bda5d908f1 // indirect
k8s.io/utils v0.0.0-20221011040102-427025108f67 // indirect
sigs.k8s.io/structured-merge-diff/v3 v3.0.1 // indirect
sigs.k8s.io/yaml v1.2.0 // indirect
k8s.io/klog/v2 v2.90.1 // indirect
k8s.io/kube-openapi v0.0.0-20230501164219-8b0f38b5fd1f // indirect
k8s.io/utils v0.0.0-20230209194617-a36077c30491 // indirect
sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd // indirect
sigs.k8s.io/structured-merge-diff/v4 v4.2.3 // indirect
sigs.k8s.io/yaml v1.3.0 // indirect
)

814
go.sum

File diff suppressed because it is too large Load Diff

View File

@@ -34,7 +34,12 @@ type SetFactory interface {
SetFactory(tls TLSFactory)
}
// Deprecated: Use NewListenerWithChain instead as it supports intermediate CAs
func NewListener(l net.Listener, storage TLSStorage, caCert *x509.Certificate, caKey crypto.Signer, config Config) (net.Listener, http.Handler, error) {
return NewListenerWithChain(l, storage, []*x509.Certificate{caCert}, caKey, config)
}
func NewListenerWithChain(l net.Listener, storage TLSStorage, caCert []*x509.Certificate, caKey crypto.Signer, config Config) (net.Listener, http.Handler, error) {
if config.CN == "" {
config.CN = "dynamic"
}
@@ -58,6 +63,7 @@ func NewListener(l net.Listener, storage TLSStorage, caCert *x509.Certificate, c
ExpirationDaysCheck: config.ExpirationDaysCheck,
},
Listener: l,
certReady: make(chan struct{}),
storage: &nonNil{storage: storage},
sans: config.SANs,
maxSANs: config.MaxSANs,
@@ -154,6 +160,7 @@ type listener struct {
version string
tlsConfig *tls.Config
cert *tls.Certificate
certReady chan struct{}
sans []string
maxSANs int
init sync.Once
@@ -162,9 +169,12 @@ type listener struct {
func (l *listener) WrapExpiration(days int) net.Listener {
ctx, cancel := context.WithCancel(context.Background())
go func() {
// loop on short sleeps until certificate preload completes
for l.cert == nil {
time.Sleep(time.Millisecond)
// wait for cert to be set, this will unblock when the channel is closed
select {
case <-ctx.Done():
return
case <-l.certReady:
}
for {
@@ -448,7 +458,12 @@ func (l *listener) loadCert(currentConn net.Conn) (*tls.Certificate, error) {
l.connLock.Unlock()
}
// we can only close the ready channel once when the cert is first assigned
canClose := l.cert == nil
l.cert = &cert
if canClose {
close(l.certReady)
}
l.version = secret.ResourceVersion
return l.cert, nil
}

View File

@@ -21,6 +21,8 @@ import (
)
type ListenOpts struct {
CAChain []*x509.Certificate
// Deprecated: Use CAChain instead
CA *x509.Certificate
CAKey crypto.Signer
Storage dynamiclistener.TLSStorage
@@ -132,7 +134,7 @@ func getTLSListener(ctx context.Context, tcp net.Listener, handler http.Handler,
return nil, nil, err
}
listener, dynHandler, err := dynamiclistener.NewListener(tcp, storage, caCert, caKey, opts.TLSListenerConfig)
listener, dynHandler, err := dynamiclistener.NewListenerWithChain(tcp, storage, caCert, caKey, opts.TLSListenerConfig)
if err != nil {
return nil, nil, err
}
@@ -140,13 +142,17 @@ func getTLSListener(ctx context.Context, tcp net.Listener, handler http.Handler,
return listener, wrapHandler(dynHandler, handler), nil
}
func getCA(opts ListenOpts) (*x509.Certificate, crypto.Signer, error) {
if opts.CA != nil && opts.CAKey != nil {
return opts.CA, opts.CAKey, nil
func getCA(opts ListenOpts) ([]*x509.Certificate, crypto.Signer, error) {
if opts.CAKey != nil {
if opts.CAChain != nil {
return opts.CAChain, opts.CAKey, nil
} else if opts.CA != nil {
return []*x509.Certificate{opts.CA}, opts.CAKey, nil
}
}
if opts.Secrets == nil {
return factory.LoadOrGenCA()
return factory.LoadOrGenCAChain()
}
if opts.CAName == "" {
@@ -161,7 +167,7 @@ func getCA(opts ListenOpts) (*x509.Certificate, crypto.Signer, error) {
opts.CANamespace = "kube-system"
}
return kubernetes.LoadOrGenCA(opts.Secrets, opts.CANamespace, opts.CAName)
return kubernetes.LoadOrGenCAChain(opts.Secrets, opts.CANamespace, opts.CAName)
}
func newStorage(ctx context.Context, opts ListenOpts) dynamiclistener.TLSStorage {

View File

@@ -11,12 +11,21 @@ import (
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
)
// Deprecated: Use LoadOrGenCAChain instead as it supports intermediate CAs
func LoadOrGenCA(secrets v1controller.SecretClient, namespace, name string) (*x509.Certificate, crypto.Signer, error) {
chain, signer, err := LoadOrGenCAChain(secrets, namespace, name)
if err != nil {
return nil, nil, err
}
return chain[0], signer, err
}
func LoadOrGenCAChain(secrets v1controller.SecretClient, namespace, name string) ([]*x509.Certificate, crypto.Signer, error) {
secret, err := getSecret(secrets, namespace, name)
if err != nil {
return nil, nil, err
}
return factory.LoadCA(secret.Data[v1.TLSCertKey], secret.Data[v1.TLSPrivateKeyKey])
return factory.LoadCAChain(secret.Data[v1.TLSCertKey], secret.Data[v1.TLSPrivateKeyKey])
}
func LoadOrGenClient(secrets v1controller.SecretClient, namespace, name, cn string, ca *x509.Certificate, key crypto.Signer) (*x509.Certificate, crypto.Signer, error) {