Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion pkg/deployment/reconcile/action_tls_ca_append.go
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@ func (a *appendTLSCACertificateAction) Start(ctx context.Context) (bool, error)
return true, nil
}

ca, _, err := getKeyCertFromSecret(a.log, caSecret, resources.CACertName, resources.CAKeyName)
ca, _, err := resources.GetKeyCertFromSecret(a.log, caSecret, resources.CACertName, resources.CAKeyName)
if err != nil {
a.log.Warn().Err(err).Msgf("Cert %s is invalid", resources.GetCASecretName(a.actionCtx.GetAPIObject()))
return true, nil
Expand Down
2 changes: 1 addition & 1 deletion pkg/deployment/reconcile/action_tls_ca_clean.go
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,7 @@ func (a *cleanTLSCACertificateAction) Start(ctx context.Context) (bool, error) {
return true, nil
}

ca, _, err := getKeyCertFromSecret(a.log, caSecret, resources.CACertName, resources.CAKeyName)
ca, _, err := resources.GetKeyCertFromSecret(a.log, caSecret, resources.CACertName, resources.CAKeyName)
if err != nil {
a.log.Warn().Err(err).Msgf("Cert %s is invalid", resources.GetCASecretName(a.actionCtx.GetAPIObject()))
return true, nil
Expand Down
7 changes: 4 additions & 3 deletions pkg/deployment/reconcile/action_tls_status_update.go
Original file line number Diff line number Diff line change
Expand Up @@ -65,19 +65,20 @@ func (a *tlsKeyStatusUpdateAction) Start(ctx context.Context) (bool, error) {
keyHashes := secretKeysToListWithPrefix("sha256:", f)

if err = a.actionCtx.WithStatusUpdate(func(s *api.DeploymentStatus) bool {
r := false
if len(keyHashes) == 1 {
if s.Hashes.TLS.CA == nil || *s.Hashes.TLS.CA != keyHashes[0] {
s.Hashes.TLS.CA = util.NewString(keyHashes[0])
return true
r = true
}
}

if !util.CompareStringArray(keyHashes, s.Hashes.TLS.Truststore) {
s.Hashes.TLS.Truststore = keyHashes
return true
r = true
}

return false
return r
}); err != nil {
return false, err
}
Expand Down
127 changes: 6 additions & 121 deletions pkg/deployment/reconcile/plan_builder_tls.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,11 +23,9 @@
package reconcile

import (
"bytes"
"context"
"crypto/tls"
"crypto/x509"
"encoding/pem"
"fmt"
"net/http"
"net/url"
Expand All @@ -37,129 +35,16 @@ import (
"github.com/arangodb/kube-arangodb/pkg/deployment/client"
"github.com/arangodb/kube-arangodb/pkg/util/constants"

"github.com/arangodb-helper/go-certificates"
api "github.com/arangodb/kube-arangodb/pkg/apis/deployment/v1"
"github.com/arangodb/kube-arangodb/pkg/deployment/resources"
"github.com/arangodb/kube-arangodb/pkg/deployment/resources/inspector"
"github.com/arangodb/kube-arangodb/pkg/util"
"github.com/pkg/errors"
core "k8s.io/api/core/v1"

api "github.com/arangodb/kube-arangodb/pkg/apis/deployment/v1"
"github.com/arangodb/kube-arangodb/pkg/util/k8sutil"
"github.com/rs/zerolog"
)

const CertificateRenewalMargin = 7 * 24 * time.Hour

type Certificates []*x509.Certificate

func (c Certificates) Contains(cert *x509.Certificate) bool {
for _, localCert := range c {
if !localCert.Equal(cert) {
return false
}
}

return true
}

func (c Certificates) ContainsAll(certs Certificates) bool {
if len(certs) == 0 {
return true
}

for _, cert := range certs {
if !c.Contains(cert) {
return false
}
}

return true
}

func (c Certificates) ToPem() ([]byte, error) {
bytes := bytes.NewBuffer([]byte{})

for _, cert := range c {
if err := pem.Encode(bytes, &pem.Block{Type: "CERTIFICATE", Bytes: cert.Raw}); err != nil {
return nil, err
}
}

return bytes.Bytes(), nil
}

func (c Certificates) AsCertPool() *x509.CertPool {
cp := x509.NewCertPool()

for _, cert := range c {
cp.AddCert(cert)
}

return cp
}

func getCertsFromData(log zerolog.Logger, caPem []byte) Certificates {
certs := make([]*x509.Certificate, 0, 2)

for {
pem, rest := pem.Decode(caPem)
if pem == nil {
break
}

caPem = rest

cert, err := x509.ParseCertificate(pem.Bytes)
if err != nil {
// This error should be ignored
log.Error().Err(err).Msg("Unable to parse certificate")
continue
}

certs = append(certs, cert)
}

return certs
}

func getCertsFromSecret(log zerolog.Logger, secret *core.Secret) Certificates {
caPem, exists := secret.Data[core.ServiceAccountRootCAKey]
if !exists {
return nil
}

return getCertsFromData(log, caPem)
}

func getKeyCertFromCache(log zerolog.Logger, cachedStatus inspector.Inspector, spec api.DeploymentSpec, certName, keyName string) (Certificates, interface{}, error) {
caSecret, exists := cachedStatus.Secret(spec.TLS.GetCASecretName())
if !exists {
return nil, nil, errors.Errorf("CA Secret does not exists")
}

return getKeyCertFromSecret(log, caSecret, keyName, certName)
}

func getKeyCertFromSecret(log zerolog.Logger, secret *core.Secret, certName, keyName string) (Certificates, interface{}, error) {
ca, exists := secret.Data[certName]
if !exists {
return nil, nil, errors.Errorf("Key %s missing in secret", certName)
}

key, exists := secret.Data[keyName]
if !exists {
return nil, nil, errors.Errorf("Key %s missing in secret", keyName)
}

cert, keys, err := certificates.LoadFromPEM(string(ca), string(key))
if err != nil {
return nil, nil, err
}

return cert, keys, nil
}

// createTLSStatusUpdate creates plan to update ca info
func createTLSStatusUpdate(ctx context.Context,
log zerolog.Logger, apiObject k8sutil.APIObject,
Expand Down Expand Up @@ -228,7 +113,7 @@ func createCAAppendPlan(ctx context.Context,
return nil
}

ca, _, err := getKeyCertFromSecret(log, caSecret, resources.CACertName, resources.CAKeyName)
ca, _, err := resources.GetKeyCertFromSecret(log, caSecret, resources.CACertName, resources.CAKeyName)
if err != nil {
log.Warn().Err(err).Str("secret", spec.TLS.GetCASecretName()).Msg("CA Secret does not contains Cert")
return nil
Expand Down Expand Up @@ -281,7 +166,7 @@ func createCARenewalPlan(ctx context.Context,
return nil
}

cas, _, err := getKeyCertFromSecret(log, caSecret, resources.CACertName, resources.CAKeyName)
cas, _, err := resources.GetKeyCertFromSecret(log, caSecret, resources.CACertName, resources.CAKeyName)
if err != nil {
log.Warn().Err(err).Str("secret", spec.TLS.GetCASecretName()).Msg("CA Secret does not contains Cert")
return nil
Expand Down Expand Up @@ -312,7 +197,7 @@ func createCACleanPlan(ctx context.Context,
return nil
}

ca, _, err := getKeyCertFromSecret(log, caSecret, resources.CACertName, resources.CAKeyName)
ca, _, err := resources.GetKeyCertFromSecret(log, caSecret, resources.CACertName, resources.CAKeyName)
if err != nil {
log.Warn().Err(err).Str("secret", spec.TLS.GetCASecretName()).Msg("CA Secret does not contains Cert")
return nil
Expand Down Expand Up @@ -461,7 +346,7 @@ func createKeyfileRenewalPlanMode(
return mode
}

func checkServerValidCertRequest(ctx context.Context, apiObject k8sutil.APIObject, group api.ServerGroup, member api.MemberStatus, ca Certificates) (*tls.ConnectionState, error) {
func checkServerValidCertRequest(ctx context.Context, apiObject k8sutil.APIObject, group api.ServerGroup, member api.MemberStatus, ca resources.Certificates) (*tls.ConnectionState, error) {
endpoint := fmt.Sprintf("https://%s:%d", k8sutil.CreatePodDNSName(apiObject, group.AsRole(), member.ID), k8sutil.ArangoPort)

tlsConfig := &tls.Config{
Expand Down Expand Up @@ -493,7 +378,7 @@ func keyfileRenewalRequired(ctx context.Context,
return false, false
}

ca, _, err := getKeyCertFromSecret(log, caSecret, resources.CACertName, resources.CAKeyName)
ca, _, err := resources.GetKeyCertFromSecret(log, caSecret, resources.CACertName, resources.CAKeyName)
if err != nil {
log.Warn().Err(err).Str("secret", spec.TLS.GetCASecretName()).Msg("CA Secret does not contains Cert")
return false, false
Expand Down
145 changes: 145 additions & 0 deletions pkg/deployment/resources/certicicates.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,145 @@
//
// DISCLAIMER
//
// Copyright 2020 ArangoDB GmbH, Cologne, Germany
//
// 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.
//
// Copyright holder is ArangoDB GmbH, Cologne, Germany
//
// Author Adam Janikowski
//

package resources

import (
"bytes"
"crypto/x509"
"encoding/pem"

"github.com/arangodb-helper/go-certificates"
api "github.com/arangodb/kube-arangodb/pkg/apis/deployment/v1"
"github.com/arangodb/kube-arangodb/pkg/deployment/resources/inspector"
"github.com/pkg/errors"
"github.com/rs/zerolog"
core "k8s.io/api/core/v1"
)

type Certificates []*x509.Certificate

func (c Certificates) Contains(cert *x509.Certificate) bool {
for _, localCert := range c {
if !localCert.Equal(cert) {
return false
}
}

return true
}

func (c Certificates) ContainsAll(certs Certificates) bool {
if len(certs) == 0 {
return true
}

for _, cert := range certs {
if !c.Contains(cert) {
return false
}
}

return true
}

func (c Certificates) ToPem() ([]byte, error) {
bytes := bytes.NewBuffer([]byte{})

for _, cert := range c {
if err := pem.Encode(bytes, &pem.Block{Type: "CERTIFICATE", Bytes: cert.Raw}); err != nil {
return nil, err
}
}

return bytes.Bytes(), nil
}

func (c Certificates) AsCertPool() *x509.CertPool {
cp := x509.NewCertPool()

for _, cert := range c {
cp.AddCert(cert)
}

return cp
}

func GetCertsFromData(log zerolog.Logger, caPem []byte) Certificates {
certs := make([]*x509.Certificate, 0, 2)

for {
pem, rest := pem.Decode(caPem)
if pem == nil {
break
}

caPem = rest

cert, err := x509.ParseCertificate(pem.Bytes)
if err != nil {
// This error should be ignored
log.Error().Err(err).Msg("Unable to parse certificate")
continue
}

certs = append(certs, cert)
}

return certs
}

func GetCertsFromSecret(log zerolog.Logger, secret *core.Secret) Certificates {
caPem, exists := secret.Data[core.ServiceAccountRootCAKey]
if !exists {
return nil
}

return GetCertsFromData(log, caPem)
}

func GetKeyCertFromCache(log zerolog.Logger, cachedStatus inspector.Inspector, spec api.DeploymentSpec, certName, keyName string) (Certificates, interface{}, error) {
caSecret, exists := cachedStatus.Secret(spec.TLS.GetCASecretName())
if !exists {
return nil, nil, errors.Errorf("CA Secret does not exists")
}

return GetKeyCertFromSecret(log, caSecret, keyName, certName)
}

func GetKeyCertFromSecret(log zerolog.Logger, secret *core.Secret, certName, keyName string) (Certificates, interface{}, error) {
ca, exists := secret.Data[certName]
if !exists {
return nil, nil, errors.Errorf("Key %s missing in secret", certName)
}

key, exists := secret.Data[keyName]
if !exists {
return nil, nil, errors.Errorf("Key %s missing in secret", keyName)
}

cert, keys, err := certificates.LoadFromPEM(string(ca), string(key))
if err != nil {
return nil, nil, err
}

return cert, keys, nil
}
Loading