mirror of
https://github.com/k3s-io/k3s.git
synced 2024-06-07 19:41:36 +00:00
Update dynamiclistener
Second round of fixes for #1621 Signed-off-by: Brad Davidson <brad.davidson@rancher.com>
This commit is contained in:
parent
7fb1797fd3
commit
b1d017f892
2
go.mod
2
go.mod
@ -94,7 +94,7 @@ require (
|
|||||||
github.com/opencontainers/runc v1.0.0-rc10
|
github.com/opencontainers/runc v1.0.0-rc10
|
||||||
github.com/opencontainers/selinux v1.5.3-0.20200613095409-bb88c45a3863
|
github.com/opencontainers/selinux v1.5.3-0.20200613095409-bb88c45a3863
|
||||||
github.com/pkg/errors v0.9.1
|
github.com/pkg/errors v0.9.1
|
||||||
github.com/rancher/dynamiclistener v0.2.1-0.20200418023342-52ede5ec9234
|
github.com/rancher/dynamiclistener v0.2.1
|
||||||
github.com/rancher/helm-controller v0.6.5
|
github.com/rancher/helm-controller v0.6.5
|
||||||
github.com/rancher/kine v0.4.0
|
github.com/rancher/kine v0.4.0
|
||||||
github.com/rancher/remotedialer v0.2.0
|
github.com/rancher/remotedialer v0.2.0
|
||||||
|
4
go.sum
4
go.sum
@ -630,8 +630,8 @@ github.com/rancher/cri v1.3.0-k3s.7 h1:5V/AVFLCpYIsJMavJKjKpwrQU92e87dhWSX43N4q8
|
|||||||
github.com/rancher/cri v1.3.0-k3s.7/go.mod h1:Ht5T1dIKzm+4NExmb7wDVG6qR+j0xeXIjjhCv1d9geY=
|
github.com/rancher/cri v1.3.0-k3s.7/go.mod h1:Ht5T1dIKzm+4NExmb7wDVG6qR+j0xeXIjjhCv1d9geY=
|
||||||
github.com/rancher/cri-tools v1.18.0-k3s1 h1:pLYthxpSu6k3Up9tNAMA0MK2ERqB6FC1sZQPRSW1qSg=
|
github.com/rancher/cri-tools v1.18.0-k3s1 h1:pLYthxpSu6k3Up9tNAMA0MK2ERqB6FC1sZQPRSW1qSg=
|
||||||
github.com/rancher/cri-tools v1.18.0-k3s1/go.mod h1:Ij/GWNRcEDP6zVN6eQpvN/s0nhuJVtPQFy7RAdl+Wu8=
|
github.com/rancher/cri-tools v1.18.0-k3s1/go.mod h1:Ij/GWNRcEDP6zVN6eQpvN/s0nhuJVtPQFy7RAdl+Wu8=
|
||||||
github.com/rancher/dynamiclistener v0.2.1-0.20200418023342-52ede5ec9234 h1:wZ1Zh7fI7B9hfZw9Ouhz7171CZKu6XffM3ysUhhO6i0=
|
github.com/rancher/dynamiclistener v0.2.1 h1:QiY1jxs2TOLrKB04G36vE2ehEvPMPGiWp8zEHLKB1nE=
|
||||||
github.com/rancher/dynamiclistener v0.2.1-0.20200418023342-52ede5ec9234/go.mod h1:9WusTANoiRr8cDWCTtf5txieulezHbpv4vhLADPp0zU=
|
github.com/rancher/dynamiclistener v0.2.1/go.mod h1:9WusTANoiRr8cDWCTtf5txieulezHbpv4vhLADPp0zU=
|
||||||
github.com/rancher/flannel v0.12.0-k3s1 h1:P23dWSk/9mGT1x2rDWW9JXNrF/0kjftiHwMau/+ZLGM=
|
github.com/rancher/flannel v0.12.0-k3s1 h1:P23dWSk/9mGT1x2rDWW9JXNrF/0kjftiHwMau/+ZLGM=
|
||||||
github.com/rancher/flannel v0.12.0-k3s1/go.mod h1:zQ/9Uhaw0yV4Wh6ljVwHVT1x5KuhenZA+6L8lRzOJEY=
|
github.com/rancher/flannel v0.12.0-k3s1/go.mod h1:zQ/9Uhaw0yV4Wh6ljVwHVT1x5KuhenZA+6L8lRzOJEY=
|
||||||
github.com/rancher/go-powershell v0.0.0-20200701182037-6845e6fcfa79 h1:UeC0rjrIel8hHz92cdVN09Cm4Hz+BhsPP/ZvQnPOr58=
|
github.com/rancher/go-powershell v0.0.0-20200701182037-6845e6fcfa79 h1:UeC0rjrIel8hHz92cdVN09Cm4Hz+BhsPP/ZvQnPOr58=
|
||||||
|
@ -39,7 +39,7 @@ func (c *Cluster) newListener(ctx context.Context) (net.Listener, http.Handler,
|
|||||||
CipherSuites: c.config.TLSCipherSuites,
|
CipherSuites: c.config.TLSCipherSuites,
|
||||||
},
|
},
|
||||||
SANs: append(c.config.SANs, "localhost", "kubernetes", "kubernetes.default", "kubernetes.default.svc."+c.config.ClusterDomain),
|
SANs: append(c.config.SANs, "localhost", "kubernetes", "kubernetes.default", "kubernetes.default.svc."+c.config.ClusterDomain),
|
||||||
ExpirationDaysCheck: 90,
|
ExpirationDaysCheck: config.CertificateRenewDays,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -20,6 +20,7 @@ const (
|
|||||||
FlannelBackendHostGW = "host-gw"
|
FlannelBackendHostGW = "host-gw"
|
||||||
FlannelBackendIPSEC = "ipsec"
|
FlannelBackendIPSEC = "ipsec"
|
||||||
FlannelBackendWireguard = "wireguard"
|
FlannelBackendWireguard = "wireguard"
|
||||||
|
CertificateRenewDays = 90
|
||||||
)
|
)
|
||||||
|
|
||||||
type Node struct {
|
type Node struct {
|
||||||
|
@ -898,7 +898,7 @@ func expired(certFile string, pool *x509.CertPool) bool {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
return certutil.IsCertExpired(certificates[0])
|
return certutil.IsCertExpired(certificates[0], config.CertificateRenewDays)
|
||||||
}
|
}
|
||||||
|
|
||||||
func cloudControllerManager(ctx context.Context, cfg *config.Control, runtime *config.ControlRuntime) {
|
func cloudControllerManager(ctx context.Context, cfg *config.Control, runtime *config.ControlRuntime) {
|
||||||
|
26
vendor/github.com/rancher/dynamiclistener/cert/cert.go
generated
vendored
26
vendor/github.com/rancher/dynamiclistener/cert/cert.go
generated
vendored
@ -33,7 +33,7 @@ import (
|
|||||||
"math"
|
"math"
|
||||||
"math/big"
|
"math/big"
|
||||||
"net"
|
"net"
|
||||||
"path"
|
"path/filepath"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
@ -45,6 +45,10 @@ const (
|
|||||||
duration365d = time.Hour * 24 * 365
|
duration365d = time.Hour * 24 * 365
|
||||||
)
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
ErrStaticCert = errors.New("cannot renew static certificate")
|
||||||
|
)
|
||||||
|
|
||||||
// Config contains the basic fields required for creating a certificate
|
// Config contains the basic fields required for creating a certificate
|
||||||
type Config struct {
|
type Config struct {
|
||||||
CommonName string
|
CommonName string
|
||||||
@ -119,7 +123,13 @@ func NewSignedCert(cfg Config, key crypto.Signer, caCert *x509.Certificate, caKe
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
return x509.ParseCertificate(certDERBytes)
|
|
||||||
|
parsedCert, err := x509.ParseCertificate(certDERBytes)
|
||||||
|
if err == nil {
|
||||||
|
logrus.Infof("certificate %s signed by %s: notBefore=%s notAfter=%s",
|
||||||
|
parsedCert.Subject, caCert.Subject, parsedCert.NotBefore, parsedCert.NotAfter)
|
||||||
|
}
|
||||||
|
return parsedCert, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// MakeEllipticPrivateKeyPEM creates an ECDSA private key
|
// MakeEllipticPrivateKeyPEM creates an ECDSA private key
|
||||||
@ -161,8 +171,8 @@ func GenerateSelfSignedCertKeyWithFixtures(host string, alternateIPs []net.IP, a
|
|||||||
maxAge := time.Hour * 24 * 365 // one year self-signed certs
|
maxAge := time.Hour * 24 * 365 // one year self-signed certs
|
||||||
|
|
||||||
baseName := fmt.Sprintf("%s_%s_%s", host, strings.Join(ipsToStrings(alternateIPs), "-"), strings.Join(alternateDNS, "-"))
|
baseName := fmt.Sprintf("%s_%s_%s", host, strings.Join(ipsToStrings(alternateIPs), "-"), strings.Join(alternateDNS, "-"))
|
||||||
certFixturePath := path.Join(fixtureDirectory, baseName+".crt")
|
certFixturePath := filepath.Join(fixtureDirectory, baseName+".crt")
|
||||||
keyFixturePath := path.Join(fixtureDirectory, baseName+".key")
|
keyFixturePath := filepath.Join(fixtureDirectory, baseName+".key")
|
||||||
if len(fixtureDirectory) > 0 {
|
if len(fixtureDirectory) > 0 {
|
||||||
cert, err := ioutil.ReadFile(certFixturePath)
|
cert, err := ioutil.ReadFile(certFixturePath)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
@ -271,11 +281,11 @@ func ipsToStrings(ips []net.IP) []string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// IsCertExpired checks if the certificate about to expire
|
// IsCertExpired checks if the certificate about to expire
|
||||||
func IsCertExpired(cert *x509.Certificate) bool {
|
func IsCertExpired(cert *x509.Certificate, days int) bool {
|
||||||
expirationDate := cert.NotAfter
|
expirationDate := cert.NotAfter
|
||||||
diffDays := expirationDate.Sub(time.Now()).Hours() / 24.0
|
diffDays := time.Until(expirationDate).Hours() / 24.0
|
||||||
if diffDays <= 90 {
|
if diffDays <= float64(days) {
|
||||||
logrus.Infof("certificate will expire in %f days", diffDays)
|
logrus.Infof("certificate %s will expire in %f days at %s", cert.Subject, diffDays, cert.NotAfter)
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
return false
|
return false
|
||||||
|
6
vendor/github.com/rancher/dynamiclistener/cert/io.go
generated
vendored
6
vendor/github.com/rancher/dynamiclistener/cert/io.go
generated
vendored
@ -34,15 +34,15 @@ func CanReadCertAndKey(certPath, keyPath string) (bool, error) {
|
|||||||
certReadable := canReadFile(certPath)
|
certReadable := canReadFile(certPath)
|
||||||
keyReadable := canReadFile(keyPath)
|
keyReadable := canReadFile(keyPath)
|
||||||
|
|
||||||
if certReadable == false && keyReadable == false {
|
if !certReadable && !keyReadable {
|
||||||
return false, nil
|
return false, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
if certReadable == false {
|
if !certReadable {
|
||||||
return false, fmt.Errorf("error reading %s, certificate and key must be supplied as a pair", certPath)
|
return false, fmt.Errorf("error reading %s, certificate and key must be supplied as a pair", certPath)
|
||||||
}
|
}
|
||||||
|
|
||||||
if keyReadable == false {
|
if !keyReadable {
|
||||||
return false, fmt.Errorf("error reading %s, certificate and key must be supplied as a pair", keyPath)
|
return false, fmt.Errorf("error reading %s, certificate and key must be supplied as a pair", keyPath)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
34
vendor/github.com/rancher/dynamiclistener/factory/cert_utils.go
generated
vendored
34
vendor/github.com/rancher/dynamiclistener/factory/cert_utils.go
generated
vendored
@ -11,6 +11,8 @@ import (
|
|||||||
"math/big"
|
"math/big"
|
||||||
"net"
|
"net"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/sirupsen/logrus"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
@ -40,6 +42,31 @@ func NewSelfSignedCACert(key crypto.Signer, cn string, org ...string) (*x509.Cer
|
|||||||
return x509.ParseCertificate(certDERBytes)
|
return x509.ParseCertificate(certDERBytes)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func NewSignedClientCert(signer crypto.Signer, caCert *x509.Certificate, caKey crypto.Signer, cn string) (*x509.Certificate, error) {
|
||||||
|
serialNumber, err := rand.Int(rand.Reader, new(big.Int).SetInt64(math.MaxInt64))
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
parent := x509.Certificate{
|
||||||
|
ExtKeyUsage: []x509.ExtKeyUsage{x509.ExtKeyUsageClientAuth},
|
||||||
|
KeyUsage: x509.KeyUsageKeyEncipherment | x509.KeyUsageDigitalSignature,
|
||||||
|
NotAfter: time.Now().Add(time.Hour * 24 * 365).UTC(),
|
||||||
|
NotBefore: caCert.NotBefore,
|
||||||
|
SerialNumber: serialNumber,
|
||||||
|
Subject: pkix.Name{
|
||||||
|
CommonName: cn,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
cert, err := x509.CreateCertificate(rand.Reader, &parent, caCert, signer.Public(), caKey)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return x509.ParseCertificate(cert)
|
||||||
|
}
|
||||||
|
|
||||||
func NewSignedCert(signer crypto.Signer, caCert *x509.Certificate, caKey crypto.Signer, cn string, orgs []string,
|
func NewSignedCert(signer crypto.Signer, caCert *x509.Certificate, caKey crypto.Signer, cn string, orgs []string,
|
||||||
domains []string, ips []net.IP) (*x509.Certificate, error) {
|
domains []string, ips []net.IP) (*x509.Certificate, error) {
|
||||||
|
|
||||||
@ -67,7 +94,12 @@ func NewSignedCert(signer crypto.Signer, caCert *x509.Certificate, caKey crypto.
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
return x509.ParseCertificate(cert)
|
parsedCert, err := x509.ParseCertificate(cert)
|
||||||
|
if err == nil {
|
||||||
|
logrus.Infof("certificate %s signed by %s: notBefore=%s notAfter=%s",
|
||||||
|
parsedCert.Subject, caCert.Subject, parsedCert.NotBefore, parsedCert.NotAfter)
|
||||||
|
}
|
||||||
|
return parsedCert, err
|
||||||
}
|
}
|
||||||
|
|
||||||
func ParseCertPEM(pemCerts []byte) (*x509.Certificate, error) {
|
func ParseCertPEM(pemCerts []byte) (*x509.Certificate, error) {
|
||||||
|
77
vendor/github.com/rancher/dynamiclistener/factory/gen.go
generated
vendored
77
vendor/github.com/rancher/dynamiclistener/factory/gen.go
generated
vendored
@ -5,10 +5,10 @@ import (
|
|||||||
"crypto/ecdsa"
|
"crypto/ecdsa"
|
||||||
"crypto/elliptic"
|
"crypto/elliptic"
|
||||||
"crypto/rand"
|
"crypto/rand"
|
||||||
"crypto/sha256"
|
"crypto/sha1"
|
||||||
"crypto/x509"
|
"crypto/x509"
|
||||||
"encoding/hex"
|
|
||||||
"encoding/pem"
|
"encoding/pem"
|
||||||
|
"fmt"
|
||||||
"net"
|
"net"
|
||||||
"regexp"
|
"regexp"
|
||||||
"sort"
|
"sort"
|
||||||
@ -20,9 +20,9 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
cnPrefix = "listener.cattle.io/cn-"
|
cnPrefix = "listener.cattle.io/cn-"
|
||||||
Static = "listener.cattle.io/static"
|
Static = "listener.cattle.io/static"
|
||||||
hashKey = "listener.cattle.io/hash"
|
fingerprint = "listener.cattle.io/fingerprint"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
@ -49,16 +49,14 @@ func cns(secret *v1.Secret) (cns []string) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func collectCNs(secret *v1.Secret) (domains []string, ips []net.IP, hash string, err error) {
|
func collectCNs(secret *v1.Secret) (domains []string, ips []net.IP, err error) {
|
||||||
var (
|
var (
|
||||||
cns = cns(secret)
|
cns = cns(secret)
|
||||||
digest = sha256.New()
|
|
||||||
)
|
)
|
||||||
|
|
||||||
sort.Strings(cns)
|
sort.Strings(cns)
|
||||||
|
|
||||||
for _, v := range cns {
|
for _, v := range cns {
|
||||||
digest.Write([]byte(v))
|
|
||||||
ip := net.ParseIP(v)
|
ip := net.ParseIP(v)
|
||||||
if ip == nil {
|
if ip == nil {
|
||||||
domains = append(domains, v)
|
domains = append(domains, v)
|
||||||
@ -67,40 +65,61 @@ func collectCNs(secret *v1.Secret) (domains []string, ips []net.IP, hash string,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
hash = hex.EncodeToString(digest.Sum(nil))
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Merge combines the SAN lists from the target and additional Secrets, and returns a potentially modified Secret,
|
||||||
|
// along with a bool indicating if the returned Secret has been updated or not. If the two SAN lists alread matched
|
||||||
|
// and no merging was necessary, but the Secrets' certificate fingerprints differed, the second secret is returned
|
||||||
|
// and the updated bool is set to true despite neither certificate having actually been modified. This is required
|
||||||
|
// to support handling certificate renewal within the kubernetes storage provider.
|
||||||
func (t *TLS) Merge(target, additional *v1.Secret) (*v1.Secret, bool, error) {
|
func (t *TLS) Merge(target, additional *v1.Secret) (*v1.Secret, bool, error) {
|
||||||
return t.AddCN(target, cns(additional)...)
|
secret, updated, err := t.AddCN(target, cns(additional)...)
|
||||||
|
if !updated {
|
||||||
|
if target.Annotations[fingerprint] != additional.Annotations[fingerprint] {
|
||||||
|
secret = additional
|
||||||
|
updated = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return secret, updated, err
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *TLS) Refresh(secret *v1.Secret) (*v1.Secret, error) {
|
// Renew returns a copy of the given certificate that has been re-signed
|
||||||
|
// to extend the NotAfter date. It is an error to attempt to renew
|
||||||
|
// a static (user-provided) certificate.
|
||||||
|
func (t *TLS) Renew(secret *v1.Secret) (*v1.Secret, error) {
|
||||||
|
if IsStatic(secret) {
|
||||||
|
return secret, cert.ErrStaticCert
|
||||||
|
}
|
||||||
cns := cns(secret)
|
cns := cns(secret)
|
||||||
secret = secret.DeepCopy()
|
secret = secret.DeepCopy()
|
||||||
secret.Annotations = map[string]string{}
|
secret.Annotations = map[string]string{}
|
||||||
secret, _, err := t.AddCN(secret, cns...)
|
secret, _, err := t.generateCert(secret, cns...)
|
||||||
return secret, err
|
return secret, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Filter ensures that the CNs are all valid accorting to both internal logic, and any filter callbacks.
|
||||||
|
// The returned list will contain only approved CN entries.
|
||||||
func (t *TLS) Filter(cn ...string) []string {
|
func (t *TLS) Filter(cn ...string) []string {
|
||||||
if t.FilterCN == nil {
|
if len(cn) == 0 || t.FilterCN == nil {
|
||||||
return cn
|
return cn
|
||||||
}
|
}
|
||||||
return t.FilterCN(cn...)
|
return t.FilterCN(cn...)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// AddCN attempts to add a list of CN strings to a given Secret, returning the potentially-modified
|
||||||
|
// Secret along with a bool indicating whether or not it has been updated. The Secret will not be changed
|
||||||
|
// if it has an attribute indicating that it is static (aka user-provided), or if no new CNs were added.
|
||||||
func (t *TLS) AddCN(secret *v1.Secret, cn ...string) (*v1.Secret, bool, error) {
|
func (t *TLS) AddCN(secret *v1.Secret, cn ...string) (*v1.Secret, bool, error) {
|
||||||
var (
|
|
||||||
err error
|
|
||||||
)
|
|
||||||
|
|
||||||
cn = t.Filter(cn...)
|
cn = t.Filter(cn...)
|
||||||
|
|
||||||
if !NeedsUpdate(0, secret, cn...) {
|
if IsStatic(secret) || !NeedsUpdate(0, secret, cn...) {
|
||||||
return secret, false, nil
|
return secret, false, nil
|
||||||
}
|
}
|
||||||
|
return t.generateCert(secret, cn...)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *TLS) generateCert(secret *v1.Secret, cn ...string) (*v1.Secret, bool, error) {
|
||||||
secret = secret.DeepCopy()
|
secret = secret.DeepCopy()
|
||||||
if secret == nil {
|
if secret == nil {
|
||||||
secret = &v1.Secret{}
|
secret = &v1.Secret{}
|
||||||
@ -113,7 +132,7 @@ func (t *TLS) AddCN(secret *v1.Secret, cn ...string) (*v1.Secret, bool, error) {
|
|||||||
return nil, false, err
|
return nil, false, err
|
||||||
}
|
}
|
||||||
|
|
||||||
domains, ips, hash, err := collectCNs(secret)
|
domains, ips, err := collectCNs(secret)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, false, err
|
return nil, false, err
|
||||||
}
|
}
|
||||||
@ -133,7 +152,7 @@ func (t *TLS) AddCN(secret *v1.Secret, cn ...string) (*v1.Secret, bool, error) {
|
|||||||
}
|
}
|
||||||
secret.Data[v1.TLSCertKey] = certBytes
|
secret.Data[v1.TLSCertKey] = certBytes
|
||||||
secret.Data[v1.TLSPrivateKeyKey] = keyBytes
|
secret.Data[v1.TLSPrivateKeyKey] = keyBytes
|
||||||
secret.Annotations[hashKey] = hash
|
secret.Annotations[fingerprint] = fmt.Sprintf("SHA1=%X", sha1.Sum(newCert.Raw))
|
||||||
|
|
||||||
return secret, true, nil
|
return secret, true, nil
|
||||||
}
|
}
|
||||||
@ -157,15 +176,21 @@ func populateCN(secret *v1.Secret, cn ...string) *v1.Secret {
|
|||||||
return secret
|
return secret
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// IsStatic returns true if the Secret has an attribute indicating that it contains
|
||||||
|
// a static (aka user-provided) certificate, which should not be modified.
|
||||||
|
func IsStatic(secret *v1.Secret) bool {
|
||||||
|
return secret.Annotations[Static] == "true"
|
||||||
|
}
|
||||||
|
|
||||||
|
// NeedsUpdate returns true if any of the CNs are not currently present on the
|
||||||
|
// secret's Certificate, as recorded in the cnPrefix annotations. It will return
|
||||||
|
// false if all requested CNs are already present, or if maxSANs is non-zero and has
|
||||||
|
// been exceeded.
|
||||||
func NeedsUpdate(maxSANs int, secret *v1.Secret, cn ...string) bool {
|
func NeedsUpdate(maxSANs int, secret *v1.Secret, cn ...string) bool {
|
||||||
if secret == nil {
|
if secret == nil {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
if secret.Annotations[Static] == "true" {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, cn := range cn {
|
for _, cn := range cn {
|
||||||
if secret.Annotations[cnPrefix+cn] == "" {
|
if secret.Annotations[cnPrefix+cn] == "" {
|
||||||
if maxSANs > 0 && len(cns(secret)) >= maxSANs {
|
if maxSANs > 0 && len(cns(secret)) >= maxSANs {
|
||||||
@ -192,6 +217,7 @@ func getPrivateKey(secret *v1.Secret) (crypto.Signer, error) {
|
|||||||
return NewPrivateKey()
|
return NewPrivateKey()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Marshal returns the given cert and key as byte slices.
|
||||||
func Marshal(x509Cert *x509.Certificate, privateKey crypto.Signer) ([]byte, []byte, error) {
|
func Marshal(x509Cert *x509.Certificate, privateKey crypto.Signer) ([]byte, []byte, error) {
|
||||||
certBlock := pem.Block{
|
certBlock := pem.Block{
|
||||||
Type: CertificateBlockType,
|
Type: CertificateBlockType,
|
||||||
@ -206,6 +232,7 @@ func Marshal(x509Cert *x509.Certificate, privateKey crypto.Signer) ([]byte, []by
|
|||||||
return pem.EncodeToMemory(&certBlock), keyBytes, nil
|
return pem.EncodeToMemory(&certBlock), keyBytes, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// NewPrivateKey returnes a new ECDSA key
|
||||||
func NewPrivateKey() (crypto.Signer, error) {
|
func NewPrivateKey() (crypto.Signer, error) {
|
||||||
return ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
|
return ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
|
||||||
}
|
}
|
||||||
|
46
vendor/github.com/rancher/dynamiclistener/listener.go
generated
vendored
46
vendor/github.com/rancher/dynamiclistener/listener.go
generated
vendored
@ -11,6 +11,7 @@ import (
|
|||||||
"sync"
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/rancher/dynamiclistener/cert"
|
||||||
"github.com/rancher/dynamiclistener/factory"
|
"github.com/rancher/dynamiclistener/factory"
|
||||||
"github.com/sirupsen/logrus"
|
"github.com/sirupsen/logrus"
|
||||||
v1 "k8s.io/api/core/v1"
|
v1 "k8s.io/api/core/v1"
|
||||||
@ -22,7 +23,7 @@ type TLSStorage interface {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type TLSFactory interface {
|
type TLSFactory interface {
|
||||||
Refresh(secret *v1.Secret) (*v1.Secret, error)
|
Renew(secret *v1.Secret) (*v1.Secret, error)
|
||||||
AddCN(secret *v1.Secret, cn ...string) (*v1.Secret, bool, error)
|
AddCN(secret *v1.Secret, cn ...string) (*v1.Secret, bool, error)
|
||||||
Merge(target *v1.Secret, additional *v1.Secret) (*v1.Secret, bool, error)
|
Merge(target *v1.Secret, additional *v1.Secret) (*v1.Secret, bool, error)
|
||||||
Filter(cn ...string) []string
|
Filter(cn ...string) []string
|
||||||
@ -152,13 +153,18 @@ type listener struct {
|
|||||||
func (l *listener) WrapExpiration(days int) net.Listener {
|
func (l *listener) WrapExpiration(days int) net.Listener {
|
||||||
ctx, cancel := context.WithCancel(context.Background())
|
ctx, cancel := context.WithCancel(context.Background())
|
||||||
go func() {
|
go func() {
|
||||||
time.Sleep(5 * time.Minute)
|
time.Sleep(30 * time.Second)
|
||||||
|
|
||||||
for {
|
for {
|
||||||
wait := 6 * time.Hour
|
wait := 6 * time.Hour
|
||||||
if err := l.checkExpiration(days); err != nil {
|
if err := l.checkExpiration(days); err != nil {
|
||||||
logrus.Errorf("failed to check and refresh dynamic cert: %v", err)
|
logrus.Errorf("failed to check and renew dynamic cert: %v", err)
|
||||||
wait = 5 + time.Minute
|
// Don't go into short retry loop if we're using a static (user-provided) cert.
|
||||||
|
// We will still check and print an error every six hours until the user updates the secret with
|
||||||
|
// a cert that is not about to expire. Hopefully this will prompt them to take action.
|
||||||
|
if err != cert.ErrStaticCert {
|
||||||
|
wait = 5 * time.Minute
|
||||||
|
}
|
||||||
}
|
}
|
||||||
select {
|
select {
|
||||||
case <-ctx.Done():
|
case <-ctx.Done():
|
||||||
@ -191,22 +197,26 @@ func (l *listener) checkExpiration(days int) error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
cert, err := tls.X509KeyPair(secret.Data[v1.TLSCertKey], secret.Data[v1.TLSPrivateKeyKey])
|
keyPair, err := tls.X509KeyPair(secret.Data[v1.TLSCertKey], secret.Data[v1.TLSPrivateKeyKey])
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
certParsed, err := x509.ParseCertificate(cert.Certificate[0])
|
certParsed, err := x509.ParseCertificate(keyPair.Certificate[0])
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
if time.Now().UTC().Add(time.Hour * 24 * time.Duration(days)).After(certParsed.NotAfter) {
|
if cert.IsCertExpired(certParsed, days) {
|
||||||
secret, err := l.factory.Refresh(secret)
|
secret, err := l.factory.Renew(secret)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
return l.storage.Update(secret)
|
if err := l.storage.Update(secret); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
// clear version to force cert reload
|
||||||
|
l.version = ""
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
@ -304,7 +314,7 @@ func (l *listener) updateCert(cn ...string) error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
if !factory.NeedsUpdate(l.maxSANs, secret, cn...) {
|
if !factory.IsStatic(secret) && !factory.NeedsUpdate(l.maxSANs, secret, cn...) {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -324,13 +334,6 @@ func (l *listener) updateCert(cn ...string) error {
|
|||||||
}
|
}
|
||||||
// clear version to force cert reload
|
// clear version to force cert reload
|
||||||
l.version = ""
|
l.version = ""
|
||||||
if l.conns != nil {
|
|
||||||
l.connLock.Lock()
|
|
||||||
for _, conn := range l.conns {
|
|
||||||
_ = conn.close()
|
|
||||||
}
|
|
||||||
l.connLock.Unlock()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
@ -366,6 +369,15 @@ func (l *listener) loadCert() (*tls.Certificate, error) {
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// cert has changed, close closeWrapper wrapped connections
|
||||||
|
if l.conns != nil {
|
||||||
|
l.connLock.Lock()
|
||||||
|
for _, conn := range l.conns {
|
||||||
|
_ = conn.close()
|
||||||
|
}
|
||||||
|
l.connLock.Unlock()
|
||||||
|
}
|
||||||
|
|
||||||
l.cert = &cert
|
l.cert = &cert
|
||||||
l.version = secret.ResourceVersion
|
l.version = secret.ResourceVersion
|
||||||
return l.cert, nil
|
return l.cert, nil
|
||||||
|
66
vendor/github.com/rancher/dynamiclistener/storage/kubernetes/ca.go
generated
vendored
66
vendor/github.com/rancher/dynamiclistener/storage/kubernetes/ca.go
generated
vendored
@ -19,27 +19,46 @@ func LoadOrGenCA(secrets v1controller.SecretClient, namespace, name string) (*x5
|
|||||||
return factory.LoadCA(secret.Data[v1.TLSCertKey], secret.Data[v1.TLSPrivateKeyKey])
|
return factory.LoadCA(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) {
|
||||||
|
secret, err := getClientSecret(secrets, namespace, name, cn, ca, key)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
return factory.LoadCA(secret.Data[v1.TLSCertKey], secret.Data[v1.TLSPrivateKeyKey])
|
||||||
|
}
|
||||||
|
|
||||||
|
func getClientSecret(secrets v1controller.SecretClient, namespace, name, cn string, caCert *x509.Certificate, caKey crypto.Signer) (*v1.Secret, error) {
|
||||||
|
s, err := secrets.Get(namespace, name, metav1.GetOptions{})
|
||||||
|
if !errors.IsNotFound(err) {
|
||||||
|
return s, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return createAndStoreClientCert(secrets, namespace, name, cn, caCert, caKey)
|
||||||
|
}
|
||||||
|
|
||||||
func getSecret(secrets v1controller.SecretClient, namespace, name string) (*v1.Secret, error) {
|
func getSecret(secrets v1controller.SecretClient, namespace, name string) (*v1.Secret, error) {
|
||||||
s, err := secrets.Get(namespace, name, metav1.GetOptions{})
|
s, err := secrets.Get(namespace, name, metav1.GetOptions{})
|
||||||
if !errors.IsNotFound(err) {
|
if !errors.IsNotFound(err) {
|
||||||
return s, err
|
return s, err
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := createAndStore(secrets, namespace, name); err != nil {
|
return createAndStore(secrets, namespace, name)
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return secrets.Get(namespace, name, metav1.GetOptions{})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func createAndStore(secrets v1controller.SecretClient, namespace string, name string) error {
|
func createAndStoreClientCert(secrets v1controller.SecretClient, namespace string, name, cn string, caCert *x509.Certificate, caKey crypto.Signer) (*v1.Secret, error) {
|
||||||
ca, cert, err := factory.GenCA()
|
key, err := factory.NewPrivateKey()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
certPem, keyPem, err := factory.Marshal(ca, cert)
|
cert, err := factory.NewSignedClientCert(key, caCert, caKey, cn)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
certPem, keyPem, err := factory.Marshal(cert, key)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
secret := &v1.Secret{
|
secret := &v1.Secret{
|
||||||
@ -54,6 +73,31 @@ func createAndStore(secrets v1controller.SecretClient, namespace string, name st
|
|||||||
Type: v1.SecretTypeTLS,
|
Type: v1.SecretTypeTLS,
|
||||||
}
|
}
|
||||||
|
|
||||||
secrets.Create(secret)
|
return secrets.Create(secret)
|
||||||
return nil
|
}
|
||||||
|
|
||||||
|
func createAndStore(secrets v1controller.SecretClient, namespace string, name string) (*v1.Secret, error) {
|
||||||
|
ca, cert, err := factory.GenCA()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
certPem, keyPem, err := factory.Marshal(ca, cert)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
secret := &v1.Secret{
|
||||||
|
ObjectMeta: metav1.ObjectMeta{
|
||||||
|
Name: name,
|
||||||
|
Namespace: namespace,
|
||||||
|
},
|
||||||
|
Data: map[string][]byte{
|
||||||
|
v1.TLSCertKey: certPem,
|
||||||
|
v1.TLSPrivateKeyKey: keyPem,
|
||||||
|
},
|
||||||
|
Type: v1.SecretTypeTLS,
|
||||||
|
}
|
||||||
|
|
||||||
|
return secrets.Create(secret)
|
||||||
}
|
}
|
||||||
|
5
vendor/github.com/rancher/dynamiclistener/storage/kubernetes/controller.go
generated
vendored
5
vendor/github.com/rancher/dynamiclistener/storage/kubernetes/controller.go
generated
vendored
@ -156,10 +156,9 @@ func (s *storage) saveInK8s(secret *v1.Secret) (*v1.Secret, error) {
|
|||||||
if targetSecret.UID == "" {
|
if targetSecret.UID == "" {
|
||||||
logrus.Infof("Creating new TLS secret for %v (count: %d): %v", targetSecret.Name, len(targetSecret.Annotations)-1, targetSecret.Annotations)
|
logrus.Infof("Creating new TLS secret for %v (count: %d): %v", targetSecret.Name, len(targetSecret.Annotations)-1, targetSecret.Annotations)
|
||||||
return s.secrets.Create(targetSecret)
|
return s.secrets.Create(targetSecret)
|
||||||
} else {
|
|
||||||
logrus.Infof("Updating TLS secret for %v (count: %d): %v", targetSecret.Name, len(targetSecret.Annotations)-1, targetSecret.Annotations)
|
|
||||||
return s.secrets.Update(targetSecret)
|
|
||||||
}
|
}
|
||||||
|
logrus.Infof("Updating TLS secret for %v (count: %d): %v", targetSecret.Name, len(targetSecret.Annotations)-1, targetSecret.Annotations)
|
||||||
|
return s.secrets.Update(targetSecret)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *storage) Update(secret *v1.Secret) (err error) {
|
func (s *storage) Update(secret *v1.Secret) (err error) {
|
||||||
|
14
vendor/github.com/rancher/dynamiclistener/storage/memory/memory.go
generated
vendored
14
vendor/github.com/rancher/dynamiclistener/storage/memory/memory.go
generated
vendored
@ -32,13 +32,15 @@ func (m *memory) Get() (*v1.Secret, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (m *memory) Update(secret *v1.Secret) error {
|
func (m *memory) Update(secret *v1.Secret) error {
|
||||||
if m.storage != nil {
|
if m.secret == nil || m.secret.ResourceVersion != secret.ResourceVersion {
|
||||||
if err := m.storage.Update(secret); err != nil {
|
if m.storage != nil {
|
||||||
return err
|
if err := m.storage.Update(secret); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
logrus.Infof("Active TLS secret %s (ver=%s) (count %d): %v", secret.Name, secret.ResourceVersion, len(secret.Annotations)-1, secret.Annotations)
|
logrus.Infof("Active TLS secret %s (ver=%s) (count %d): %v", secret.Name, secret.ResourceVersion, len(secret.Annotations)-1, secret.Annotations)
|
||||||
m.secret = secret
|
m.secret = secret
|
||||||
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
2
vendor/modules.txt
vendored
2
vendor/modules.txt
vendored
@ -726,7 +726,7 @@ github.com/prometheus/procfs/xfs
|
|||||||
# github.com/rakelkar/gonetsh v0.0.0-20190930180311-e5c5ffe4bdf0
|
# github.com/rakelkar/gonetsh v0.0.0-20190930180311-e5c5ffe4bdf0
|
||||||
github.com/rakelkar/gonetsh/netroute
|
github.com/rakelkar/gonetsh/netroute
|
||||||
github.com/rakelkar/gonetsh/netsh
|
github.com/rakelkar/gonetsh/netsh
|
||||||
# github.com/rancher/dynamiclistener v0.2.1-0.20200418023342-52ede5ec9234
|
# github.com/rancher/dynamiclistener v0.2.1
|
||||||
github.com/rancher/dynamiclistener
|
github.com/rancher/dynamiclistener
|
||||||
github.com/rancher/dynamiclistener/cert
|
github.com/rancher/dynamiclistener/cert
|
||||||
github.com/rancher/dynamiclistener/factory
|
github.com/rancher/dynamiclistener/factory
|
||||||
|
Loading…
Reference in New Issue
Block a user