123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153 |
- /*
- Copyright 2016 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 signer implements a CA signer that uses keys stored on local disk.
- package signer
- import (
- "crypto"
- "crypto/x509"
- "fmt"
- "io/ioutil"
- "os"
- "time"
- capi "k8s.io/api/certificates/v1beta1"
- certificatesinformers "k8s.io/client-go/informers/certificates/v1beta1"
- clientset "k8s.io/client-go/kubernetes"
- "k8s.io/kubernetes/pkg/controller/certificates"
- "github.com/cloudflare/cfssl/config"
- "github.com/cloudflare/cfssl/helpers"
- "github.com/cloudflare/cfssl/signer"
- "github.com/cloudflare/cfssl/signer/local"
- )
- func NewCSRSigningController(
- client clientset.Interface,
- csrInformer certificatesinformers.CertificateSigningRequestInformer,
- caFile, caKeyFile string,
- certificateDuration time.Duration,
- ) (*certificates.CertificateController, error) {
- signer, err := newCFSSLSigner(caFile, caKeyFile, client, certificateDuration)
- if err != nil {
- return nil, err
- }
- return certificates.NewCertificateController(
- client,
- csrInformer,
- signer.handle,
- ), nil
- }
- type cfsslSigner struct {
- ca *x509.Certificate
- priv crypto.Signer
- sigAlgo x509.SignatureAlgorithm
- client clientset.Interface
- certificateDuration time.Duration
- // nowFn returns the current time. We have here for unit testing
- nowFn func() time.Time
- }
- func newCFSSLSigner(caFile, caKeyFile string, client clientset.Interface, certificateDuration time.Duration) (*cfsslSigner, error) {
- ca, err := ioutil.ReadFile(caFile)
- if err != nil {
- return nil, fmt.Errorf("error reading CA cert file %q: %v", caFile, err)
- }
- cakey, err := ioutil.ReadFile(caKeyFile)
- if err != nil {
- return nil, fmt.Errorf("error reading CA key file %q: %v", caKeyFile, err)
- }
- parsedCa, err := helpers.ParseCertificatePEM(ca)
- if err != nil {
- return nil, fmt.Errorf("error parsing CA cert file %q: %v", caFile, err)
- }
- strPassword := os.Getenv("CFSSL_CA_PK_PASSWORD")
- password := []byte(strPassword)
- if strPassword == "" {
- password = nil
- }
- priv, err := helpers.ParsePrivateKeyPEMWithPassword(cakey, password)
- if err != nil {
- return nil, fmt.Errorf("Malformed private key %v", err)
- }
- return &cfsslSigner{
- priv: priv,
- ca: parsedCa,
- sigAlgo: signer.DefaultSigAlgo(priv),
- client: client,
- certificateDuration: certificateDuration,
- nowFn: time.Now,
- }, nil
- }
- func (s *cfsslSigner) handle(csr *capi.CertificateSigningRequest) error {
- if !certificates.IsCertificateRequestApproved(csr) {
- return nil
- }
- csr, err := s.sign(csr)
- if err != nil {
- return fmt.Errorf("error auto signing csr: %v", err)
- }
- _, err = s.client.CertificatesV1beta1().CertificateSigningRequests().UpdateStatus(csr)
- if err != nil {
- return fmt.Errorf("error updating signature for csr: %v", err)
- }
- return nil
- }
- func (s *cfsslSigner) sign(csr *capi.CertificateSigningRequest) (*capi.CertificateSigningRequest, error) {
- var usages []string
- for _, usage := range csr.Spec.Usages {
- usages = append(usages, string(usage))
- }
- certExpiryDuration := s.certificateDuration
- durationUntilExpiry := s.ca.NotAfter.Sub(s.nowFn())
- if durationUntilExpiry <= 0 {
- return nil, fmt.Errorf("the signer has expired: %v", s.ca.NotAfter)
- }
- if durationUntilExpiry < certExpiryDuration {
- certExpiryDuration = durationUntilExpiry
- }
- policy := &config.Signing{
- Default: &config.SigningProfile{
- Usage: usages,
- Expiry: certExpiryDuration,
- ExpiryString: certExpiryDuration.String(),
- },
- }
- cfs, err := local.NewSigner(s.priv, s.ca, s.sigAlgo, policy)
- if err != nil {
- return nil, err
- }
- csr.Status.Certificate, err = cfs.Sign(signer.SignRequest{
- Request: string(csr.Spec.Request),
- })
- if err != nil {
- return nil, err
- }
- return csr, nil
- }
|