@@ -3,7 +3,9 @@ package clusterapi
33import (
44 "bytes"
55 "context"
6+ "crypto/x509"
67 "encoding/json"
8+ "encoding/pem"
79 "fmt"
810 "io"
911 "net"
@@ -15,6 +17,7 @@ import (
1517 "text/template"
1618 "time"
1719
20+ "github.com/Azure/azure-sdk-for-go/sdk/azidentity"
1821 "github.com/pkg/errors"
1922 "github.com/sirupsen/logrus"
2023 "sigs.k8s.io/controller-runtime/pkg/client"
@@ -231,6 +234,28 @@ func (c *system) Run(ctx context.Context) error { //nolint:gocyclo
231234 }
232235 }
233236
237+ // ASO expects the contents of the cert--not the path--in the env var.
238+ // Since .pfx is a binary format, we need to parse it and convert to PEM format.
239+ var certPEM string
240+ if session .AuthType == azic .ClientCertificateAuth {
241+ certPath := session .Credentials .ClientCertificatePath
242+ certData , err := os .ReadFile (certPath )
243+ if err != nil {
244+ return fmt .Errorf ("unable to read client certificate contents from %s: %w" , certPath , err )
245+ }
246+
247+ // Parse the .pfx file to get certificates and private key
248+ certs , key , err := azidentity .ParseCertificates (certData , []byte (session .Credentials .ClientCertificatePassword ))
249+ if err != nil {
250+ return fmt .Errorf ("failed to parse client certificate: %w" , err )
251+ }
252+
253+ // Convert certificates and key to PEM format
254+ certPEM , err = certificatesToPEM (certs , key )
255+ if err != nil {
256+ return fmt .Errorf ("failed to convert certificate to PEM: %w" , err )
257+ }
258+ }
234259 controllers = append (controllers ,
235260 c .getInfrastructureController (
236261 & azProvider ,
@@ -259,7 +284,7 @@ func (c *system) Run(ctx context.Context) error { //nolint:gocyclo
259284 "POD_NAMESPACE" : "capz-system" ,
260285 "AZURE_CLIENT_ID" : session .Credentials .ClientID ,
261286 "AZURE_CLIENT_SECRET" : session .Credentials .ClientSecret ,
262- "AZURE_CLIENT_CERTIFICATE" : session . Credentials . ClientCertificatePath ,
287+ "AZURE_CLIENT_CERTIFICATE" : certPEM ,
263288 "AZURE_CLIENT_CERTIFICATE_PASSWORD" : session .Credentials .ClientCertificatePassword ,
264289 "AZURE_TENANT_ID" : session .Credentials .TenantID ,
265290 "AZURE_SUBSCRIPTION_ID" : session .Credentials .SubscriptionID ,
@@ -685,3 +710,34 @@ func (c *system) runController(ctx context.Context, ct *controller) error {
685710 ct .state = pr
686711 return nil
687712}
713+
714+ // certificatesToPEM converts x509 certificates and a private key to PEM format.
715+ // The output is a concatenated string of PEM-encoded certificates followed by the PEM-encoded private key.
716+ func certificatesToPEM (certs []* x509.Certificate , key any ) (string , error ) {
717+ var pemData strings.Builder
718+
719+ // Encode each certificate
720+ for _ , cert := range certs {
721+ if err := pem .Encode (& pemData , & pem.Block {
722+ Type : "CERTIFICATE" ,
723+ Bytes : cert .Raw ,
724+ }); err != nil {
725+ return "" , fmt .Errorf ("failed to encode certificate: %w" , err )
726+ }
727+ }
728+
729+ // Encode the private key
730+ keyBytes , err := x509 .MarshalPKCS8PrivateKey (key )
731+ if err != nil {
732+ return "" , fmt .Errorf ("failed to marshal private key: %w" , err )
733+ }
734+
735+ if err := pem .Encode (& pemData , & pem.Block {
736+ Type : "PRIVATE KEY" ,
737+ Bytes : keyBytes ,
738+ }); err != nil {
739+ return "" , fmt .Errorf ("failed to encode private key: %w" , err )
740+ }
741+
742+ return pemData .String (), nil
743+ }
0 commit comments