pkg/controller/keyvault/kv_util.go (108 lines of code) (raw):

package keyvault import ( "encoding/json" "fmt" "net/url" "strings" "github.com/Azure/aks-app-routing-operator/api/v1alpha1" "github.com/Azure/aks-app-routing-operator/pkg/util" kvcsi "github.com/Azure/secrets-store-csi-driver-provider-azure/pkg/provider/types" v1 "k8s.io/api/networking/v1" "sigs.k8s.io/controller-runtime/pkg/client" gatewayv1 "sigs.k8s.io/gateway-api/apis/v1" secv1 "sigs.k8s.io/secrets-store-csi-driver/apis/v1" ) var nginxNamePrefix = "keyvault-nginx-" type spcConfig struct { ClientId string TenantId string KeyvaultCertUri string Name string Cloud string } func shouldDeploySpc(obj client.Object) bool { switch t := obj.(type) { case *v1alpha1.NginxIngressController: if t.Spec.DefaultSSLCertificate == nil || t.Spec.DefaultSSLCertificate.KeyVaultURI == nil || *t.Spec.DefaultSSLCertificate.KeyVaultURI == "" { return false } return true case *v1.Ingress: if t.Annotations == nil || t.Annotations["kubernetes.azure.com/tls-cert-keyvault-uri"] == "" { return false } return true default: return false } } func buildSPC(spc *secv1.SecretProviderClass, spcConfig spcConfig) error { certURI := spcConfig.KeyvaultCertUri uri, err := url.Parse(certURI) if err != nil { return util.NewUserError(err, fmt.Sprintf("unable to parse certificate uri: %s", certURI)) } vaultName := strings.Split(uri.Host, ".")[0] chunks := strings.Split(uri.Path, "/") if len(chunks) < 3 { return util.NewUserError(fmt.Errorf("uri Path contains too few segments: has: %d requires greater than: %d uri path: %s", len(chunks), 3, uri.Path), fmt.Sprintf("invalid secret uri: %s", certURI)) } secretName := chunks[2] p := map[string]interface{}{ "objectName": secretName, "objectType": "secret", } if len(chunks) > 3 { p["objectVersion"] = chunks[3] } params, err := json.Marshal(p) if err != nil { return err } objects, err := json.Marshal(map[string]interface{}{"array": []string{string(params)}}) if err != nil { return err } spc.Spec = secv1.SecretProviderClassSpec{ Provider: secv1.Provider("azure"), SecretObjects: []*secv1.SecretObject{{ SecretName: spcConfig.Name, Type: "kubernetes.io/tls", Data: []*secv1.SecretObjectData{ { ObjectName: secretName, Key: "tls.key", }, { ObjectName: secretName, Key: "tls.crt", }, }, }}, // https://azure.github.io/secrets-store-csi-driver-provider-azure/docs/getting-started/usage/#create-your-own-secretproviderclass-object Parameters: map[string]string{ "keyvaultName": vaultName, "useVMManagedIdentity": "true", "userAssignedIdentityID": spcConfig.ClientId, "tenantId": spcConfig.TenantId, "objects": string(objects), }, } if spcConfig.Cloud != "" { spc.Spec.Parameters[kvcsi.CloudNameParameter] = spcConfig.Cloud } return nil } // DefaultNginxCertName returns a default name for the nginx certificate name using the IngressClassName from the spec. // Truncates characters in the IngressClassName passed the max secret length (255) if the IngressClassName and the default namespace are over the limit func DefaultNginxCertName(nic *v1alpha1.NginxIngressController) string { secretMaxSize := 255 certName := nginxNamePrefix + nic.Name if len(certName) > secretMaxSize { return certName[0:secretMaxSize] } return certName } func certSecretName(ingressName string) string { return fmt.Sprintf("keyvault-%s", ingressName) } func shouldReconcileGateway(gwObj *gatewayv1.Gateway) bool { return gwObj.Spec.GatewayClassName == istioGatewayClassName }