istio.io/istio@v0.0.0-20240520182934-d79c90f27776/security/pkg/pki/ra/common.go (about)

     1  // Copyright Istio Authors
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //	http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  package ra
    15  
    16  import (
    17  	"fmt"
    18  	"time"
    19  
    20  	clientset "k8s.io/client-go/kubernetes"
    21  
    22  	meshconfig "istio.io/api/mesh/v1alpha1"
    23  	"istio.io/istio/pkg/slices"
    24  	raerror "istio.io/istio/security/pkg/pki/error"
    25  	"istio.io/istio/security/pkg/pki/util"
    26  	caserver "istio.io/istio/security/pkg/server/ca"
    27  )
    28  
    29  // RegistrationAuthority : Registration Authority interface.
    30  type RegistrationAuthority interface {
    31  	caserver.CertificateAuthority
    32  	// SetCACertificatesFromMeshConfig sets the CACertificates using the ones from mesh config
    33  	SetCACertificatesFromMeshConfig([]*meshconfig.MeshConfig_CertificateData)
    34  	// GetRootCertFromMeshConfig returns the root cert for the specific signer in mesh config
    35  	GetRootCertFromMeshConfig(signerName string) ([]byte, error)
    36  }
    37  
    38  // CaExternalType : Type of External CA integration
    39  type CaExternalType string
    40  
    41  // IstioRAOptions : Configuration Options for the IstioRA
    42  type IstioRAOptions struct {
    43  	// ExternalCAType: Integration API type with external CA
    44  	ExternalCAType CaExternalType
    45  	// DefaultCertTTL: Default Certificate TTL
    46  	DefaultCertTTL time.Duration
    47  	// MaxCertTTL: Maximum Certificate TTL that can be requested
    48  	MaxCertTTL time.Duration
    49  	// CaCertFile : File containing PEM encoded CA root certificate of external CA
    50  	CaCertFile string
    51  	// CaSigner : To indicate custom CA Signer name when using external K8s CA
    52  	CaSigner string
    53  	// VerifyAppendCA : Whether to use caCertFile containing CA root cert to verify and append to signed cert-chain
    54  	VerifyAppendCA bool
    55  	// K8sClient : K8s API client
    56  	K8sClient clientset.Interface
    57  	// TrustDomain
    58  	TrustDomain string
    59  	// CertSignerDomain info
    60  	CertSignerDomain string
    61  }
    62  
    63  const (
    64  	// ExtCAK8s : Integrate with external CA using k8s CSR API
    65  	ExtCAK8s CaExternalType = "ISTIOD_RA_KUBERNETES_API"
    66  
    67  	// DefaultExtCACertDir : Location of external CA certificate
    68  	DefaultExtCACertDir string = "./etc/external-ca-cert"
    69  )
    70  
    71  // ValidateCSR : Validate all SAN extensions in csrPEM match authenticated identities
    72  func ValidateCSR(csrPEM []byte, subjectIDs []string) bool {
    73  	csr, err := util.ParsePemEncodedCSR(csrPEM)
    74  	if err != nil {
    75  		return false
    76  	}
    77  	if err := csr.CheckSignature(); err != nil {
    78  		return false
    79  	}
    80  	csrIDs, err := util.ExtractIDs(csr.Extensions)
    81  	if err != nil {
    82  		return false
    83  	}
    84  	for _, s1 := range csrIDs {
    85  		if !slices.Contains(subjectIDs, s1) {
    86  			return false
    87  		}
    88  	}
    89  	return true
    90  }
    91  
    92  // NewIstioRA is a factory method that returns an RA that implements the RegistrationAuthority functionality.
    93  // the caOptions defines the external provider
    94  func NewIstioRA(opts *IstioRAOptions) (RegistrationAuthority, error) {
    95  	if opts.ExternalCAType == ExtCAK8s {
    96  		istioRA, err := NewKubernetesRA(opts)
    97  		if err != nil {
    98  			return nil, fmt.Errorf("failed to create an K8s CA: %v", err)
    99  		}
   100  		return istioRA, err
   101  	}
   102  	return nil, fmt.Errorf("invalid CA Name %s", opts.ExternalCAType)
   103  }
   104  
   105  // preSign : Validation checks to execute before signing certificates
   106  func preSign(raOpts *IstioRAOptions, csrPEM []byte, subjectIDs []string, requestedLifetime time.Duration, forCA bool) (time.Duration, error) {
   107  	if forCA {
   108  		return requestedLifetime, raerror.NewError(raerror.CSRError,
   109  			fmt.Errorf("unable to generate CA certifificates"))
   110  	}
   111  	if !ValidateCSR(csrPEM, subjectIDs) {
   112  		return requestedLifetime, raerror.NewError(raerror.CSRError, fmt.Errorf(
   113  			"unable to validate SAN Identities in CSR"))
   114  	}
   115  	// If the requested requestedLifetime is non-positive, apply the default TTL.
   116  	lifetime := requestedLifetime
   117  	if requestedLifetime.Seconds() <= 0 {
   118  		lifetime = raOpts.DefaultCertTTL
   119  	}
   120  	// If the requested TTL is greater than maxCertTTL, return an error
   121  	if requestedLifetime.Seconds() > raOpts.MaxCertTTL.Seconds() {
   122  		return lifetime, raerror.NewError(raerror.TTLError, fmt.Errorf(
   123  			"requested TTL %s is greater than the max allowed TTL %s", requestedLifetime, raOpts.MaxCertTTL))
   124  	}
   125  	return lifetime, nil
   126  }