diff --git a/Dockerfile.ci-rp b/Dockerfile.ci-rp index f6a06c708a8..b4bbcc0d182 100644 --- a/Dockerfile.ci-rp +++ b/Dockerfile.ci-rp @@ -56,7 +56,7 @@ RUN go build -ldflags "-X github.com/Azure/ARO-RP/pkg/util/version.GitCommit=${A RUN go test ./test/e2e/... -tags e2e,codec.safe -c -ldflags "-X github.com/Azure/ARO-RP/pkg/util/version.GitCommit=${ARO_VERSION}" -o e2e.test # Additional tests -RUN ARO_SKIP_PKI_TESTS=true go run gotest.tools/gotestsum@v1.11.0 --format pkgname --junitfile report.xml -- -coverprofile=cover.out ./... +RUN go run gotest.tools/gotestsum@v1.11.0 --format pkgname --junitfile report.xml -- -coverprofile=cover.out ./... RUN hack/fips/validate-fips.sh ./aro ############################################################################### diff --git a/env.example b/env.example index 2f420e76437..a265550d1dc 100644 --- a/env.example +++ b/env.example @@ -3,6 +3,4 @@ export ARO_IMAGE=arointsvc.azurecr.io/aro:latest export NO_CACHE=false export AZURE_EXTENSION_DEV_SOURCES="$(pwd)/python" -export ARO_SKIP_PKI_TESTS=true - . secrets/env diff --git a/pkg/util/azureclient/applens/applens_client.go b/pkg/util/azureclient/applens/applens_client.go index 7a84fd3c122..e44bc07e774 100644 --- a/pkg/util/azureclient/applens/applens_client.go +++ b/pkg/util/azureclient/applens/applens_client.go @@ -7,7 +7,6 @@ package applens import ( "context" - "crypto/x509" "encoding/json" "fmt" "io" @@ -60,19 +59,33 @@ func NewClient(endpoint, issuerUrlTemplate, caName, scope string, cred azcore.To return &Client{endpoint: endpoint, pipeline: *pipeline}, nil } -func newPipeline(authPolicy []policy.Policy, options *ClientOptions, issuerUrlTemplate, caName string) (*runtime.Pipeline, error) { - var cp *x509.CertPool = nil - var err error = nil - if options == nil { - // if provided pki info fetch the correct cert pool - // otherwise use the default of nil - if issuerUrlTemplate != "" && caName != "" { - cp, err = pki.GetTlsCertPool(issuerUrlTemplate, caName) - if err != nil { - return nil, err - } - } - options = NewClientOptions(cp) +func getClientOptions(initialOptions *ClientOptions, issuerUrlTemplate, caName string) (*ClientOptions, error) { + if initialOptions != nil { + return initialOptions, nil + } + + if issuerUrlTemplate == "" || caName == "" { + return NewClientOptions(nil), nil + } + + url := fmt.Sprintf(issuerUrlTemplate, caName) + rootCAs, err := pki.FetchDataFromGetIssuerPki(url) + if err != nil { + return nil, err + } + + certPool, err := pki.BuildCertPoolForCaName(rootCAs) + if err != nil { + return nil, err + } + + return NewClientOptions(certPool), nil +} + +func newPipeline(authPolicy []policy.Policy, initialClientOptions *ClientOptions, issuerUrlTemplate, caName string) (*runtime.Pipeline, error) { + options, err := getClientOptions(initialClientOptions, issuerUrlTemplate, caName) + if err != nil { + return nil, err } runtimePipeline := runtime.NewPipeline( diff --git a/pkg/util/pki/fetchdata.go b/pkg/util/pki/fetchdata.go new file mode 100644 index 00000000000..08fc7a13615 --- /dev/null +++ b/pkg/util/pki/fetchdata.go @@ -0,0 +1,32 @@ +package pki + +// Copyright (c) Microsoft Corporation. +// Licensed under the Apache License 2.0. + +import ( + "encoding/json" + "io" + "net/http" +) + +// https://aka.ms/getissuers +// The v3 endpoint can be used to get ca certs +// For example https://issuer.pki.azure.com/dsms/issuercertificates?getissuersv3&caName=ame +// returns the ame certs +func FetchDataFromGetIssuerPki(url string) (*RootCAs, error) { + response, err := http.Get(url) + if err != nil { + return nil, err + } + + defer response.Body.Close() + + body, err := io.ReadAll(response.Body) + if err != nil { + return nil, err + } + + var rootCAs RootCAs + json.Unmarshal(body, &rootCAs) + return &rootCAs, nil +} diff --git a/pkg/util/pki/pki.go b/pkg/util/pki/pki.go index 66e02dcbb25..c845169a82d 100644 --- a/pkg/util/pki/pki.go +++ b/pkg/util/pki/pki.go @@ -5,17 +5,9 @@ package pki import ( "crypto/x509" - "encoding/json" "errors" - "fmt" - "io" - "net/http" - "sync" ) -var caMap map[string]x509.CertPool = make(map[string]x509.CertPool) -var mu sync.RWMutex - type RootCAs struct { RootsInfos []RootInfo `json:"RootsInfos"` } @@ -42,76 +34,8 @@ type IntermediateInfo struct { PEM string `json:"PEM"` } -// https://aka.ms/getissuers -// The v3 endpoint can be used to get ca certs -// For example https://issuer.pki.azure.com/dsms/issuercertificates?getissuersv3&caName=ame -// returns the ame certs -func FetchDataFromGetIssuerPki(url string) (*RootCAs, error) { - response, err := http.Get(url) - - if err != nil { - return nil, err - } - - defer response.Body.Close() - - if err != nil { - return nil, err - } - - // Read in certs from endpoint - body, err := io.ReadAll(response.Body) - - if err != nil { - return nil, err - } - - var rootCAs RootCAs - json.Unmarshal(body, &rootCAs) - return &rootCAs, nil -} - -func GetTlsCertPool(urlTemplate, caName string) (*x509.CertPool, error) { - url := fmt.Sprintf(urlTemplate, caName) - caCertPool, ok := getCaCertPoolFromMap(url) - if ok { - return &caCertPool, nil - } else { - caCertPool, err := buildCertPoolForCaName(url) - - if err != nil || caCertPool == nil { - return nil, err - } - - setCaCertPoolInMap(url, *caCertPool) - - return caCertPool, nil - } -} - -func getCaCertPoolFromMap(key string) (x509.CertPool, bool) { - mu.RLock() - defer mu.RUnlock() - caCertPool, ok := caMap[key] - return caCertPool, ok -} - -func setCaCertPoolInMap(key string, caCertPool x509.CertPool) { - mu.Lock() - defer mu.Unlock() - caMap[key] = caCertPool -} - -func buildCertPoolForCaName(url string) (*x509.CertPool, error) { - data, err := FetchDataFromGetIssuerPki(url) - - if err != nil { - return nil, err - } - - // Create a CertPool +func BuildCertPoolForCaName(data *RootCAs) (*x509.CertPool, error) { caCertPool, err := x509.SystemCertPool() - if err != nil { return nil, err } diff --git a/pkg/util/pki/pki_test.go b/pkg/util/pki/pki_test.go deleted file mode 100644 index c7a9d30bb29..00000000000 --- a/pkg/util/pki/pki_test.go +++ /dev/null @@ -1,61 +0,0 @@ -package pki - -// Copyright (c) Microsoft Corporation. -// Licensed under the Apache License 2.0. - -import ( - "crypto/tls" - "crypto/x509" - "fmt" - "net/http" - "os" - "testing" -) - -func TestGetTlsConfig(t *testing.T) { - if os.Getenv("ARO_SKIP_PKI_TESTS") != "" { - t.Skip("") - } - kpiUrl := "https://issuer.pki.azure.com/dsms/issuercertificates?getissuersv3&caName=%s" - testUrl := "https://diag-runtimehost-prod.trafficmanager.net" - - caName := "ame" - caCertPool, err := GetTlsCertPool(kpiUrl, caName) - - if err != nil { - t.Errorf("Expected no error, got %v", err) - } - - if caCertPool == nil { - t.Error("Expected non-nil CertPool") - } - - url := fmt.Sprintf(kpiUrl, caName) - if _, ok := caMap[url]; !ok { - t.Errorf("Expected caMap to contain entry for %s", caName) - } - - // Create a new tls.Config with the custom CA certificate - tlsConfig := &tls.Config{ - RootCAs: caCertPool, - InsecureSkipVerify: false, - } - - // Use the tls.Config with your client - client := &http.Client{ - Transport: &http.Transport{ - TLSClientConfig: tlsConfig, - }, - } - - resp, err := client.Get(testUrl) - - if err != nil { - if _, ok := err.(x509.UnknownAuthorityError); ok { - t.Errorf("Invalid SSL/TLS certificate") - } - t.Errorf("Error calling %s", testUrl) - } - - defer resp.Body.Close() -}