pkg/interceptor/secret.go (101 lines of code) (raw):

package interceptor import ( "context" "fmt" "time" triggersApi "github.com/tektoncd/triggers/pkg/apis/triggers/v1alpha1" corev1 "k8s.io/api/core/v1" k8serrors "k8s.io/apimachinery/pkg/api/errors" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" certresources "knative.dev/pkg/webhook/certificates/resources" ctrlClient "sigs.k8s.io/controller-runtime/pkg/client" ) const ( // SecretCertsName is name of secret where ca-cert, server-cert, server-key will be stored after generation. SecretCertsName = "tekton-edp-interceptor-certs" // secretServerKey is the name of the key associated with the secret's private key. secretServerKey = "server-key.pem" // SecretServerCert is the name of the key associated with the secret's public key. secretServerCert = "server-cert.pem" // SecretCACert is the name of the key associated with the certificate of the CA for the keypair. secretCACert = "ca-cert.pem" decade = 100 * 365 * 24 * time.Hour ) type CertData struct { ServerKey []byte ServerCert []byte CaCert []byte } func NewCertData(serverKey, serverCert, caCert []byte) *CertData { return &CertData{ServerKey: serverKey, ServerCert: serverCert, CaCert: caCert} } type SecretService struct { client ctrlClient.Client } func NewSecretService(client ctrlClient.Client) *SecretService { return &SecretService{client: client} } // CreateCertsSecret creates and returns a CA certificate and certificate and key for the server. // serverKey and serverCert are used by the server to establish trust for clients, CA certificate is used by the // client to verify the server authentication chain. Certificates are based on Interceptor spec. // After generation all certificates are stored in secret: SecretCertsName. func (s *SecretService) CreateCertsSecret( ctx context.Context, namespace, interceptorName string, ) (*CertData, error) { interceptor := &triggersApi.Interceptor{} err := s.client.Get(ctx, ctrlClient.ObjectKey{Namespace: namespace, Name: interceptorName}, interceptor) if err != nil { return nil, fmt.Errorf("failed to get Interceptor: %w", err) } serKey, serCert, cacert, err := certresources.CreateCerts( ctx, interceptor.Spec.ClientConfig.Service.Name, interceptor.Spec.ClientConfig.Service.Namespace, time.Now().Add(decade), ) if err != nil { return nil, fmt.Errorf("failed to create certs: %w", err) } certData := NewCertData(serKey, serCert, cacert) secret := &corev1.Secret{} err = s.client.Get(ctx, ctrlClient.ObjectKey{Namespace: namespace, Name: SecretCertsName}, secret) if err != nil { if k8serrors.IsNotFound(err) { secret.ObjectMeta = metav1.ObjectMeta{ Namespace: namespace, Name: SecretCertsName, } secret.Data = map[string][]byte{ secretServerKey: serKey, secretServerCert: serCert, secretCACert: cacert, } secret.Type = corev1.SecretTypeOpaque if err = s.client.Create(ctx, secret); err != nil { return nil, fmt.Errorf("failed to create secret: %w", err) } return certData, nil } return nil, fmt.Errorf("failed to get secret: %w", err) } secret.Data = map[string][]byte{ secretServerKey: serKey, secretServerCert: serCert, secretCACert: cacert, } if err = s.client.Update(ctx, secret); err != nil { return nil, fmt.Errorf("failed to update secret: %w", err) } return certData, nil } // UpdateCABundle updates Interceptor CaBundle spec with CA certificate. func (s *SecretService) UpdateCABundle( ctx context.Context, namespace, interceptorName string, ca []byte, ) error { interceptor := &triggersApi.Interceptor{} err := s.client.Get(ctx, ctrlClient.ObjectKey{Namespace: namespace, Name: interceptorName}, interceptor) if err != nil { return fmt.Errorf("failed to get Interceptor: %w", err) } interceptor.Spec.ClientConfig.CaBundle = ca if err = s.client.Update(ctx, interceptor); err != nil { return fmt.Errorf("failed to update Interceptor caBundle: %w", err) } return nil }