From 1c030cb54b7273959ab16cb609f221f7d6a3ede9 Mon Sep 17 00:00:00 2001 From: Joel Lopes Date: Thu, 21 Feb 2019 09:35:14 -0800 Subject: [PATCH 1/2] Use IMDS to get subscription for Azure MSI --- builder/azure/arm/builder.go | 12 +++++++-- builder/azure/arm/config_retriever.go | 39 +++++++++++++++++++++++++++ 2 files changed, 49 insertions(+), 2 deletions(-) diff --git a/builder/azure/arm/builder.go b/builder/azure/arm/builder.go index 48c19263e..f6f3a1f33 100644 --- a/builder/azure/arm/builder.go +++ b/builder/azure/arm/builder.go @@ -59,8 +59,10 @@ func (b *Builder) Run(ui packer.Ui, hook packer.Hook, cache packer.Cache) (packe b.ctxCancel = cancel defer cancel() - if err := newConfigRetriever().FillParameters(b.config); err != nil { - return nil, err + if !b.config.useMSI() { + if err := newConfigRetriever().FillParameters(b.config); err != nil { + return nil, err + } } log.Print(":: Configuration") @@ -74,6 +76,12 @@ func (b *Builder) Run(ui packer.Ui, hook packer.Hook, cache packer.Cache) (packe return nil, err } + if b.config.useMSI() { + if err := newConfigRetriever().FillParameters(b.config); err != nil { + return nil, err + } + } + ui.Message("Creating Azure Resource Manager (ARM) client ...") azureClient, err := NewAzureClient( b.config.SubscriptionID, diff --git a/builder/azure/arm/config_retriever.go b/builder/azure/arm/config_retriever.go index 3e8a3e655..4760041d8 100644 --- a/builder/azure/arm/config_retriever.go +++ b/builder/azure/arm/config_retriever.go @@ -8,6 +8,10 @@ package arm // 1. TenantID import ( + "encoding/json" + "io/ioutil" + "net/http" + "github.com/Azure/go-autorest/autorest/azure" "github.com/hashicorp/packer/builder/azure/common" ) @@ -24,6 +28,14 @@ func newConfigRetriever() configRetriever { } func (cr configRetriever) FillParameters(c *Config) error { + if c.SubscriptionID == "" { + subscriptionID, err := cr.getSubscriptionFromIMDS() + if err != nil { + return err + } + c.SubscriptionID = subscriptionID + } + if c.TenantID == "" { tenantID, err := cr.findTenantID(*c.cloudEnvironment, c.SubscriptionID) if err != nil { @@ -34,3 +46,30 @@ func (cr configRetriever) FillParameters(c *Config) error { return nil } + +func (cr configRetriever) getSubscriptionFromIMDS() (string, error) { + client := &http.Client{} + + req, _ := http.NewRequest("GET", "http://169.254.169.254/metadata/instance/compute", nil) + req.Header.Add("Metadata", "True") + + q := req.URL.Query() + q.Add("format", "json") + q.Add("api-version", "2017-08-01") + + req.URL.RawQuery = q.Encode() + resp, err := client.Do(req) + if err != nil { + return "", err + } + + defer resp.Body.Close() + resp_body, _ := ioutil.ReadAll(resp.Body) + result := map[string]string{} + err = json.Unmarshal(resp_body, &result) + if err != nil { + return "", err + } + + return result["subscriptionId"], nil +} From c8a60c77d10817b1a4180db482ff63018ca17cb9 Mon Sep 17 00:00:00 2001 From: Joel Lopes Date: Thu, 21 Feb 2019 18:12:57 -0800 Subject: [PATCH 2/2] Add comments --- builder/azure/arm/builder.go | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/builder/azure/arm/builder.go b/builder/azure/arm/builder.go index f6f3a1f33..c591893f0 100644 --- a/builder/azure/arm/builder.go +++ b/builder/azure/arm/builder.go @@ -59,6 +59,9 @@ func (b *Builder) Run(ui packer.Ui, hook packer.Hook, cache packer.Cache) (packe b.ctxCancel = cancel defer cancel() + // User's intent to use MSI is indicated with empty subscription id, tenant, client id, client cert, client secret and jwt. + // FillParameters function will set subscription and tenant id here. Therefore getServicePrincipalTokens won't select right auth type. + // If we run this after getServicePrincipalTokens call then getServicePrincipalTokens won't have tenant id. if !b.config.useMSI() { if err := newConfigRetriever().FillParameters(b.config); err != nil { return nil, err @@ -76,6 +79,7 @@ func (b *Builder) Run(ui packer.Ui, hook packer.Hook, cache packer.Cache) (packe return nil, err } + // We need subscription id and tenant id for arm operations. Users hasn't specified one so we try to detect them here. if b.config.useMSI() { if err := newConfigRetriever().FillParameters(b.config); err != nil { return nil, err