Merge pull request #6982 from hashicorp/fix_6161
azure builder: allow to auth with managed identities ( MSI )
This commit is contained in:
commit
7643ccc67d
|
@ -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,
|
||||||
|
|
|
@ -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"))
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/////////////////////////////////////////////
|
/////////////////////////////////////////////
|
||||||
|
|
|
@ -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",
|
||||||
|
|
|
@ -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
|
||||||
|
|
||||||
|
-> 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
|
||||||
|
|
||||||
|
|
|
@ -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",
|
||||||
|
|
Loading…
Reference in New Issue