Merge pull request #6982 from hashicorp/fix_6161

azure builder: allow to auth with managed identities ( MSI )
This commit is contained in:
Megan Marsh 2018-11-12 09:03:41 -08:00 committed by GitHub
commit 7643ccc67d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 117 additions and 16 deletions

View File

@ -31,6 +31,10 @@ func (a *Authenticate) getServicePrincipalTokenWithResource(resource string) (*a
return nil, err return nil, err
} }
if a.clientID == "" && a.clientSecret == "" {
return adal.NewServicePrincipalTokenFromMSI("http://169.254.169.254/metadata/identity/oauth2/token", resource)
}
spt, err := adal.NewServicePrincipalToken( spt, err := adal.NewServicePrincipalToken(
*oauthConfig, *oauthConfig,
a.clientID, a.clientID,

View File

@ -514,17 +514,14 @@ func assertRequiredParametersSet(c *Config, errs *packer.MultiError) {
if isUseDeviceLogin(c) { if isUseDeviceLogin(c) {
c.useDeviceLogin = true c.useDeviceLogin = true
} else { } else {
if c.ClientID == "" { if c.ClientID == "" && c.ClientSecret != "" || c.ClientID != "" && c.ClientSecret == "" {
errs = packer.MultiErrorAppend(errs, fmt.Errorf("A client_id must be specified")) errs = packer.MultiErrorAppend(errs, fmt.Errorf("A client_id and client_secret must be specified together or not specified at all"))
} }
if c.ClientSecret == "" { if c.ClientID != "" && c.SubscriptionID == "" {
errs = packer.MultiErrorAppend(errs, fmt.Errorf("A client_secret must be specified")) errs = packer.MultiErrorAppend(errs, fmt.Errorf("A subscription_id must be specified when client_id & client_secret are"))
} }
if c.SubscriptionID == "" {
errs = packer.MultiErrorAppend(errs, fmt.Errorf("A subscription_id must be specified"))
}
} }
///////////////////////////////////////////// /////////////////////////////////////////////

View File

@ -124,6 +124,87 @@ func TestConfigShouldNotDefaultImageVersionIfCustomImage(t *testing.T) {
} }
} }
func Test_newConfig_MSI(t *testing.T) {
baseConfig := map[string]string{
"capture_name_prefix": "ignore",
"capture_container_name": "ignore",
"location": "ignore",
"image_url": "ignore",
"storage_account": "ignore",
"resource_group_name": "ignore",
"os_type": constants.Target_Linux,
}
tests := []struct {
name string
args []interface{}
wantErr bool
}{
{
name: "no client_id and no client_secret should enable MSI auth",
args: []interface{}{
baseConfig,
getPackerConfiguration(),
},
wantErr: false,
},
{
name: "subscription_id is will be taken from MSI",
args: []interface{}{
baseConfig,
map[string]string{
"subscription_id": "error",
},
getPackerConfiguration(),
},
wantErr: false,
},
{
name: "client_id without client_secret should error",
args: []interface{}{
baseConfig,
map[string]string{
"client_id": "error",
},
getPackerConfiguration(),
},
wantErr: true,
},
{
name: "client_secret without client_id should error",
args: []interface{}{
baseConfig,
map[string]string{
"client_secret": "error",
},
getPackerConfiguration(),
},
wantErr: true,
},
{
name: "missing subscription_id",
args: []interface{}{
baseConfig,
map[string]string{
"client_id": "ok",
"client_secret": "ok",
},
getPackerConfiguration(),
},
wantErr: true,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
_, _, err := newConfig(tt.args...)
if (err != nil) != tt.wantErr {
t.Errorf("newConfig() error = %v, wantErr %v", err, tt.wantErr)
return
}
})
}
}
func TestConfigShouldNormalizeOSTypeCase(t *testing.T) { func TestConfigShouldNormalizeOSTypeCase(t *testing.T) {
config := map[string]string{ config := map[string]string{
"capture_name_prefix": "ignore", "capture_name_prefix": "ignore",

View File

@ -59,14 +59,30 @@ mode.
> Device login mode is for the Public and US Gov clouds only. > Device login mode is for the Public and US Gov clouds only.
The device login flow asks that you open a web browser, navigate to The device login flow asks that you open a web browser, navigate to
<http://aka.ms/devicelogin>, and input the supplied code. This authorizes the <a href="http://aka.ms/devicelogin" class="uri">http://aka.ms/devicelogin</a>,
Packer for Azure application to act on your behalf. An OAuth token will be and input the supplied code. This authorizes the Packer for Azure application
created, and stored in the user's home directory to act on your behalf. An OAuth token will be created, and stored in the user's
(~/.azure/packer/oauth-TenantID.json). This token is used if the token file home directory (\~/.azure/packer/oauth-TenantID.json). This token is used if
exists, and it is refreshed as necessary. The token file prevents the need to the token file exists, and it is refreshed as necessary. The token file
continually execute the device login flow. Packer will ask for two device login prevents the need to continually execute the device login flow. Packer will ask
auth, one for service management endpoint and another for accessing temp for two device login auth, one for service management endpoint and another for
keyvault secrets that it creates. accessing temp keyvault secrets that it creates.
## Managed identities for Azure resources
-&gt; Managed identities for Azure resources is the new name for the service
formerly known as Managed Service Identity (MSI).
Managed identities is an alternative way to authorize in Azure Packer. Managed
identities for Azure resources are automatically managed by Azure and enable
you to authenticate to services that support Azure AD authentication without
needing to insert credentials into your buildfile. Navigate to
<a href="https://docs.microsoft.com/en-gb/azure/active-directory/managed-identities-azure-resources/overview"
class="uri">managed identities azure resources overview</a> to learn more about
this feature.
This feature will be used when no `subscription_id`, `client_id` or
`client_secret` is set in your buildfile.
## Install the Azure CLI ## Install the Azure CLI

View File

@ -35,7 +35,7 @@ addition to the options listed here, a
[communicator](/docs/templates/communicator.html) can be configured for this [communicator](/docs/templates/communicator.html) can be configured for this
builder. builder.
### Required: ### Required ( unless instance has [managed identities](/docs/builders/azure-setup.html#managed-identities-for-azure-resources) enabled):
- `client_id` (string) The Active Directory service principal associated with - `client_id` (string) The Active Directory service principal associated with
your builder. your builder.
@ -48,6 +48,8 @@ builder.
specified in which case it needs to have owner access to the existing specified in which case it needs to have owner access to the existing
resource group specified in build\_resource\_group\_name parameter.** resource group specified in build\_resource\_group\_name parameter.**
### Required:
- `image_publisher` (string) PublisherName for your base image. See - `image_publisher` (string) PublisherName for your base image. See
[documentation](https://azure.microsoft.com/en-us/documentation/articles/resource-groups-vm-searching/) [documentation](https://azure.microsoft.com/en-us/documentation/articles/resource-groups-vm-searching/)
for details. for details.
@ -250,6 +252,7 @@ Providing `temp_resource_group_name` or `location` in combination with
type* - the target must be a *Managed Image*. type* - the target must be a *Managed Image*.
<!-- --> <!-- -->
"shared_image_gallery": { "shared_image_gallery": {
"subscription": "00000000-0000-0000-0000-00000000000", "subscription": "00000000-0000-0000-0000-00000000000",
"resource_group": "ResourceGroup", "resource_group": "ResourceGroup",