...

Source file src/github.com/GoogleCloudPlatform/k8s-config-connector/pkg/webhook/cert/writer/secret.go

Documentation: github.com/GoogleCloudPlatform/k8s-config-connector/pkg/webhook/cert/writer

     1  /*
     2  Copyright 2018 The Kubernetes Authors.
     3  
     4  Licensed under the Apache License, Version 2.0 (the "License");
     5  you may not use this file except in compliance with the License.
     6  You may obtain a copy of the License at
     7  
     8      http://www.apache.org/licenses/LICENSE-2.0
     9  
    10  Unless required by applicable law or agreed to in writing, software
    11  distributed under the License is distributed on an "AS IS" BASIS,
    12  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13  See the License for the specific language governing permissions and
    14  limitations under the License.
    15  */
    16  
    17  package writer
    18  
    19  import (
    20  	"context"
    21  	"errors"
    22  
    23  	corev1 "k8s.io/api/core/v1"
    24  	apierrors "k8s.io/apimachinery/pkg/api/errors"
    25  	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
    26  	"k8s.io/apimachinery/pkg/types"
    27  	"sigs.k8s.io/controller-runtime/pkg/client"
    28  
    29  	"github.com/GoogleCloudPlatform/k8s-config-connector/pkg/webhook/cert/generator"
    30  )
    31  
    32  // secretCertWriter provisions the certificate by reading and writing to the k8s secrets.
    33  type secretCertWriter struct {
    34  	*SecretCertWriterOptions
    35  
    36  	// dnsName is the DNS name that the certificate is for.
    37  	dnsName string
    38  }
    39  
    40  // SecretCertWriterOptions is options for constructing a secretCertWriter.
    41  type SecretCertWriterOptions struct {
    42  	// client talks to a kubernetes cluster for creating the secret.
    43  	Client client.Client
    44  	// certGenerator generates the certificates.
    45  	CertGenerator generator.CertGenerator
    46  	// secret points the secret that contains certificates that written by the CertWriter.
    47  	Secret *types.NamespacedName
    48  }
    49  
    50  var _ CertWriter = &secretCertWriter{}
    51  
    52  func (ops *SecretCertWriterOptions) setDefaults() {
    53  	if ops.CertGenerator == nil {
    54  		ops.CertGenerator = &generator.SelfSignedCertGenerator{}
    55  	}
    56  }
    57  
    58  func (ops *SecretCertWriterOptions) validate() error {
    59  	if ops.Client == nil {
    60  		return errors.New("client must be set in SecretCertWriterOptions")
    61  	}
    62  	if ops.Secret == nil {
    63  		return errors.New("secret must be set in SecretCertWriterOptions")
    64  	}
    65  	return nil
    66  }
    67  
    68  // NewSecretCertWriter constructs a CertWriter that persists the certificate in a k8s secret.
    69  func NewSecretCertWriter(ops SecretCertWriterOptions) (CertWriter, error) {
    70  	ops.setDefaults()
    71  	err := ops.validate()
    72  	if err != nil {
    73  		return nil, err
    74  	}
    75  	return &secretCertWriter{
    76  		SecretCertWriterOptions: &ops,
    77  	}, nil
    78  }
    79  
    80  // EnsureCert provisions certificates for a webhookClientConfig by writing the certificates to a k8s secret.
    81  func (s *secretCertWriter) EnsureCert(dnsName string) (*generator.Artifacts, bool, error) {
    82  	// Create or refresh the certs based on clientConfig
    83  	s.dnsName = dnsName
    84  	return handleCommon(s.dnsName, s)
    85  }
    86  
    87  var _ certReadWriter = &secretCertWriter{}
    88  
    89  func (s *secretCertWriter) buildSecret() (*corev1.Secret, *generator.Artifacts, error) {
    90  	certs, err := s.CertGenerator.Generate(s.dnsName)
    91  	if err != nil {
    92  		return nil, nil, err
    93  	}
    94  	secret := certsToSecret(certs, *s.Secret)
    95  	return secret, certs, err
    96  }
    97  
    98  func (s *secretCertWriter) write() (*generator.Artifacts, error) {
    99  	secret, certs, err := s.buildSecret()
   100  	if err != nil {
   101  		return nil, err
   102  	}
   103  	err = s.Client.Create(context.Background(), secret)
   104  	if apierrors.IsAlreadyExists(err) {
   105  		return nil, alreadyExistError{err}
   106  	}
   107  	return certs, err
   108  }
   109  
   110  func (s *secretCertWriter) overwrite() (
   111  	*generator.Artifacts, error) {
   112  	secret, certs, err := s.buildSecret()
   113  	if err != nil {
   114  		return nil, err
   115  	}
   116  	err = s.Client.Update(context.Background(), secret)
   117  	return certs, err
   118  }
   119  
   120  func (s *secretCertWriter) read() (*generator.Artifacts, error) {
   121  	secret := &corev1.Secret{
   122  		TypeMeta: metav1.TypeMeta{
   123  			APIVersion: "v1",
   124  			Kind:       "Secret",
   125  		},
   126  	}
   127  	err := s.Client.Get(context.Background(), *s.Secret, secret)
   128  	if apierrors.IsNotFound(err) {
   129  		return nil, notFoundError{err}
   130  	}
   131  	certs := secretToCerts(secret)
   132  	if certs != nil {
   133  		// Store the CA for next usage.
   134  		s.CertGenerator.SetCA(certs.CAKey, certs.CACert)
   135  	}
   136  	return certs, nil
   137  }
   138  
   139  func secretToCerts(secret *corev1.Secret) *generator.Artifacts {
   140  	if secret.Data == nil {
   141  		return nil
   142  	}
   143  	return &generator.Artifacts{
   144  		CAKey:  secret.Data[CAKeyName],
   145  		CACert: secret.Data[CACertName],
   146  		Cert:   secret.Data[ServerCertName],
   147  		Key:    secret.Data[ServerKeyName],
   148  	}
   149  }
   150  
   151  func certsToSecret(certs *generator.Artifacts, sec types.NamespacedName) *corev1.Secret {
   152  	return &corev1.Secret{
   153  		TypeMeta: metav1.TypeMeta{
   154  			APIVersion: "v1",
   155  			Kind:       "Secret",
   156  		},
   157  		ObjectMeta: metav1.ObjectMeta{
   158  			Namespace: sec.Namespace,
   159  			Name:      sec.Name,
   160  		},
   161  		Data: map[string][]byte{
   162  			CAKeyName:      certs.CAKey,
   163  			CACertName:     certs.CACert,
   164  			ServerKeyName:  certs.Key,
   165  			ServerCertName: certs.Cert,
   166  		},
   167  	}
   168  }
   169  
   170  // Inject sets the ownerReference in the secret.
   171  func (s *secretCertWriter) Inject(objs ...client.Object) error {
   172  	// TODO: figure out how to get the UID
   173  	//for i := range objs {
   174  	//	accessor, err := meta.Accessor(objs[i])
   175  	//	if err != nil {
   176  	//		return err
   177  	//	}
   178  	//	err = controllerutil.SetControllerReference(accessor, s.sec, scheme.Scheme)
   179  	//	if err != nil {
   180  	//		return err
   181  	//	}
   182  	//}
   183  	//return s.client.Update(context.Background(), s.sec)
   184  	return nil
   185  }
   186  

View as plain text