diff --git a/cmd/kaniko-acr/main.go b/cmd/kaniko-acr/main.go index 172bbe6..913ff5e 100644 --- a/cmd/kaniko-acr/main.go +++ b/cmd/kaniko-acr/main.go @@ -9,6 +9,7 @@ import ( "net/http" "net/url" "os" + "strings" "github.com/Azure/azure-sdk-for-go/sdk/azcore/policy" "github.com/Azure/azure-sdk-for-go/sdk/azidentity" @@ -139,6 +140,11 @@ func main() { Usage: "Azure Tenant Id", EnvVar: "TENANT_ID", }, + cli.StringFlag{ + Name: "subscription-id", + Usage: "Azure Subscription Id", + EnvVar: "SUBSCRIPTION_ID", + }, cli.StringFlag{ Name: "client-id", Usage: "Azure Client Id", @@ -210,11 +216,12 @@ func run(c *cli.Context) error { registry := c.String("registry") noPush := c.Bool("no-push") - err := createDockerConfig( + publicUrl, err := setupAuth( c.String("tenant-id"), c.String("client-id"), c.String("client-cert"), c.String("client-secret"), + c.String("subscription-id"), registry, noPush, ) @@ -250,7 +257,7 @@ func run(c *cli.Context) error { Artifact: kaniko.Artifact{ Tags: c.StringSlice("tags"), Repo: c.String("repo"), - Registry: c.String("registry"), + Registry: publicUrl, ArtifactFile: c.String("artifact-file"), RegistryType: artifact.Docker, }, @@ -258,46 +265,45 @@ func run(c *cli.Context) error { return plugin.Exec() } -func createDockerConfig(tenantId, clientId, cert, - clientSecret, registry string, noPush bool) error { +func setupAuth(tenantId, clientId, cert, + clientSecret, subscriptionId, registry string, noPush bool) (string, error) { if registry == "" { - return fmt.Errorf("registry must be specified") + return "", fmt.Errorf("registry must be specified") } if noPush { - return nil + return "", nil } // case of client secret or cert based auth if clientId != "" { // only setup auth when pushing or credentials are defined - token, err := getACRToken(tenantId, clientId, clientSecret, cert, registry) + token, publicUrl, err := getACRToken(subscriptionId, tenantId, clientId, clientSecret, cert, registry) if err != nil { - return errors.Wrap(err, "failed to fetch ACR Token") + return "", errors.Wrap(err, "failed to fetch ACR Token") } err = docker.CreateDockerCfgFile(username, token, registry, dockerConfigPath) if err != nil { - return errors.Wrap(err, "failed to create docker config") + return "", errors.Wrap(err, "failed to create docker config") } + return publicUrl, nil } else { - return fmt.Errorf("managed authentication is not supported") + return "", fmt.Errorf("managed authentication is not supported") } - - return nil } -func getACRToken(tenantId, clientId, clientSecret, cert, registry string) (string, error) { +func getACRToken(subscriptionId, tenantId, clientId, clientSecret, cert, registry string) (string, string, error) { if tenantId == "" { - return "", fmt.Errorf("tenantId can't be empty for AAD authentication") + return "", "", fmt.Errorf("tenantId can't be empty for AAD authentication") } if clientId == "" { - return "", fmt.Errorf("clientId can't be empty for AAD authentication") + return "", "", fmt.Errorf("clientId can't be empty for AAD authentication") } if clientSecret == "" && cert == "" { - return "", fmt.Errorf("one of client secret or cert should be defined") + return "", "", fmt.Errorf("one of client secret or cert should be defined") } // in case of authentication via cert @@ -309,21 +315,22 @@ func getACRToken(tenantId, clientId, clientSecret, cert, registry string) (strin } if err := os.Setenv(clientIdEnv, clientId); err != nil { - return "", errors.Wrap(err, "failed to set env variable client Id") + return "", "", errors.Wrap(err, "failed to set env variable client Id") } if err := os.Setenv(clientSecretKeyEnv, clientSecret); err != nil { - return "", errors.Wrap(err, "failed to set env variable client secret") + return "", "", errors.Wrap(err, "failed to set env variable client secret") } if err := os.Setenv(tenantKeyEnv, tenantId); err != nil { - return "", errors.Wrap(err, "failed to set env variable tenant Id") + return "", "", errors.Wrap(err, "failed to set env variable tenant Id") } if err := os.Setenv(certPathEnv, ACRCertPath); err != nil { - return "", errors.Wrap(err, "failed to set env variable cert path") + return "", "", errors.Wrap(err, "failed to set env variable cert path") } env, err := azidentity.NewEnvironmentCredential(nil) if err != nil { - return "", errors.Wrap(err, "failed to get env credentials from azure") + return "", "", errors.Wrap(err, "failed to get env credentials from azure") } + policy := policy.TokenRequestOptions{ Scopes: []string{"https://management.azure.com/.default"}, } @@ -334,14 +341,20 @@ func getACRToken(tenantId, clientId, clientSecret, cert, registry string) (strin azToken, err := env.GetToken(context.Background(), policy) if err != nil { - return "", errors.Wrap(err, "failed to fetch access token") + return "", "", errors.Wrap(err, "failed to fetch access token") + } + + fmt.Fprintf(os.Stderr, "aman %s\n", azToken.Token) + publicUrl, err := getPublicUrl(azToken.Token, registry, subscriptionId) + if err != nil { + return "", "", errors.Wrap(err, "failed to fetch access token") } ACRToken, err := fetchACRToken(tenantId, azToken.Token, registry) if err != nil { - return "", errors.Wrap(err, "failed to fetch ACR token") + return "", "", errors.Wrap(err, "failed to fetch ACR token") } - return ACRToken, nil + return ACRToken, publicUrl, nil } func fetchACRToken(tenantId, token, registry string) (string, error) { @@ -385,3 +398,45 @@ func setupACRCert(cert string) error { } return nil } + +func getPublicUrl(token, registryUrl, subscriptionId string) (string, error) { + finalUrl := "https://portal.azure.com/#view/Microsoft_Azure_ContainerRegistries/TagMetadataBlade/registryId/subscriptions/%s/resourceGroups/%s/providers/Microsoft.ContainerRegistry/" + registry := strings.Split(registryUrl, ".")[0] + fmt.Fprintf(os.Stderr, "aman %s %s %s\n", registry, registryUrl, subscriptionId) + burl := "https://management.azure.com/subscriptions/" + + subscriptionId + "/resources?$filter=resourceType%20eq%20'Microsoft.ContainerRegistry/registries'%20and%20name%20eq%20'" + + registry + "'&api-version=2021-04-01&$select=id" + + method := "GET" + + client := &http.Client{} + req, err := http.NewRequest(method, burl, nil) + + if err != nil { + fmt.Println(err) + return "", errors.Wrap(err, "failed to create request for getting container registry setting") + } + req.Header.Add("Authorization", "Bearer "+token) + res, err := client.Do(req) + if err != nil { + fmt.Println(err) + return "", errors.Wrap(err, "failed to send request for getting container registry setting") + } + defer res.Body.Close() + + fmt.Fprintf(os.Stderr, "aman %d %s %s\n", res.StatusCode, strings.Split(subscriptionId, "b"), burl) + + var response strct + err = json.NewDecoder(res.Body).Decode(&response) + if err != nil { + return "", errors.Wrap(err, "failed to send request for getting container registry setting") + } + resourceGroup := response.Value[0].ID + return fmt.Sprintf(finalUrl, subscriptionId, resourceGroup), nil +} + +type strct struct { + Value []struct { + ID string `json:"id"` + } `json:"value"` +} diff --git a/pkg/artifact/artifact.go b/pkg/artifact/artifact.go index 3e4ecf9..fd166fa 100644 --- a/pkg/artifact/artifact.go +++ b/pkg/artifact/artifact.go @@ -30,6 +30,7 @@ type ( Data struct { RegistryType RegistryTypeEnum `json:"registryType"` RegistryUrl string `json:"registryUrl"` + PublicUrl string `json:"publicUrl"` Images []Image `json:"images"` } DockerArtifact struct { @@ -51,6 +52,7 @@ func WritePluginArtifactFile(registryType RegistryTypeEnum, artifactFilePath, re RegistryUrl: registryUrl, Images: images, } + fmt.Fprintf(os.Stderr, "public Url is %s\n", registryUrl) dockerArtifact := DockerArtifact{ Kind: dockerArtifactV1,