Add client_cert_token_timeout to address GH-9465 (#10528)

This commit is contained in:
Brian Farrell 2021-03-02 04:51:18 -06:00 committed by GitHub
parent 96b753f3b0
commit 273a720440
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 61 additions and 27 deletions

View File

@ -23,6 +23,7 @@ type FlatConfig struct {
ClientID *string `mapstructure:"client_id" cty:"client_id" hcl:"client_id"` ClientID *string `mapstructure:"client_id" cty:"client_id" hcl:"client_id"`
ClientSecret *string `mapstructure:"client_secret" cty:"client_secret" hcl:"client_secret"` ClientSecret *string `mapstructure:"client_secret" cty:"client_secret" hcl:"client_secret"`
ClientCertPath *string `mapstructure:"client_cert_path" cty:"client_cert_path" hcl:"client_cert_path"` ClientCertPath *string `mapstructure:"client_cert_path" cty:"client_cert_path" hcl:"client_cert_path"`
ClientCertExpireTimeout *string `mapstructure:"client_cert_token_timeout" required:"false" cty:"client_cert_token_timeout" hcl:"client_cert_token_timeout"`
ClientJWT *string `mapstructure:"client_jwt" cty:"client_jwt" hcl:"client_jwt"` ClientJWT *string `mapstructure:"client_jwt" cty:"client_jwt" hcl:"client_jwt"`
ObjectID *string `mapstructure:"object_id" cty:"object_id" hcl:"object_id"` ObjectID *string `mapstructure:"object_id" cty:"object_id" hcl:"object_id"`
TenantID *string `mapstructure:"tenant_id" required:"false" cty:"tenant_id" hcl:"tenant_id"` TenantID *string `mapstructure:"tenant_id" required:"false" cty:"tenant_id" hcl:"tenant_id"`
@ -151,6 +152,7 @@ func (*FlatConfig) HCL2Spec() map[string]hcldec.Spec {
"client_id": &hcldec.AttrSpec{Name: "client_id", Type: cty.String, Required: false}, "client_id": &hcldec.AttrSpec{Name: "client_id", Type: cty.String, Required: false},
"client_secret": &hcldec.AttrSpec{Name: "client_secret", Type: cty.String, Required: false}, "client_secret": &hcldec.AttrSpec{Name: "client_secret", Type: cty.String, Required: false},
"client_cert_path": &hcldec.AttrSpec{Name: "client_cert_path", Type: cty.String, Required: false}, "client_cert_path": &hcldec.AttrSpec{Name: "client_cert_path", Type: cty.String, Required: false},
"client_cert_token_timeout": &hcldec.AttrSpec{Name: "client_cert_token_timeout", Type: cty.String, Required: false},
"client_jwt": &hcldec.AttrSpec{Name: "client_jwt", Type: cty.String, Required: false}, "client_jwt": &hcldec.AttrSpec{Name: "client_jwt", Type: cty.String, Required: false},
"object_id": &hcldec.AttrSpec{Name: "object_id", Type: cty.String, Required: false}, "object_id": &hcldec.AttrSpec{Name: "object_id", Type: cty.String, Required: false},
"tenant_id": &hcldec.AttrSpec{Name: "tenant_id", Type: cty.String, Required: false}, "tenant_id": &hcldec.AttrSpec{Name: "tenant_id", Type: cty.String, Required: false},

View File

@ -22,6 +22,7 @@ type FlatConfig struct {
ClientID *string `mapstructure:"client_id" cty:"client_id" hcl:"client_id"` ClientID *string `mapstructure:"client_id" cty:"client_id" hcl:"client_id"`
ClientSecret *string `mapstructure:"client_secret" cty:"client_secret" hcl:"client_secret"` ClientSecret *string `mapstructure:"client_secret" cty:"client_secret" hcl:"client_secret"`
ClientCertPath *string `mapstructure:"client_cert_path" cty:"client_cert_path" hcl:"client_cert_path"` ClientCertPath *string `mapstructure:"client_cert_path" cty:"client_cert_path" hcl:"client_cert_path"`
ClientCertExpireTimeout *string `mapstructure:"client_cert_token_timeout" required:"false" cty:"client_cert_token_timeout" hcl:"client_cert_token_timeout"`
ClientJWT *string `mapstructure:"client_jwt" cty:"client_jwt" hcl:"client_jwt"` ClientJWT *string `mapstructure:"client_jwt" cty:"client_jwt" hcl:"client_jwt"`
ObjectID *string `mapstructure:"object_id" cty:"object_id" hcl:"object_id"` ObjectID *string `mapstructure:"object_id" cty:"object_id" hcl:"object_id"`
TenantID *string `mapstructure:"tenant_id" required:"false" cty:"tenant_id" hcl:"tenant_id"` TenantID *string `mapstructure:"tenant_id" required:"false" cty:"tenant_id" hcl:"tenant_id"`
@ -76,6 +77,7 @@ func (*FlatConfig) HCL2Spec() map[string]hcldec.Spec {
"client_id": &hcldec.AttrSpec{Name: "client_id", Type: cty.String, Required: false}, "client_id": &hcldec.AttrSpec{Name: "client_id", Type: cty.String, Required: false},
"client_secret": &hcldec.AttrSpec{Name: "client_secret", Type: cty.String, Required: false}, "client_secret": &hcldec.AttrSpec{Name: "client_secret", Type: cty.String, Required: false},
"client_cert_path": &hcldec.AttrSpec{Name: "client_cert_path", Type: cty.String, Required: false}, "client_cert_path": &hcldec.AttrSpec{Name: "client_cert_path", Type: cty.String, Required: false},
"client_cert_token_timeout": &hcldec.AttrSpec{Name: "client_cert_token_timeout", Type: cty.String, Required: false},
"client_jwt": &hcldec.AttrSpec{Name: "client_jwt", Type: cty.String, Required: false}, "client_jwt": &hcldec.AttrSpec{Name: "client_jwt", Type: cty.String, Required: false},
"object_id": &hcldec.AttrSpec{Name: "object_id", Type: cty.String, Required: false}, "object_id": &hcldec.AttrSpec{Name: "object_id", Type: cty.String, Required: false},
"tenant_id": &hcldec.AttrSpec{Name: "tenant_id", Type: cty.String, Required: false}, "tenant_id": &hcldec.AttrSpec{Name: "tenant_id", Type: cty.String, Required: false},

View File

@ -39,6 +39,8 @@ type Config struct {
// The path to a pem-encoded certificate that will be used to authenticate // The path to a pem-encoded certificate that will be used to authenticate
// as the specified AAD SP. // as the specified AAD SP.
ClientCertPath string `mapstructure:"client_cert_path"` ClientCertPath string `mapstructure:"client_cert_path"`
// The timeout for the JWT Token when using a [client certificate](#client_cert_path). Defaults to 1 hour.
ClientCertExpireTimeout time.Duration `mapstructure:"client_cert_token_timeout" required:"false"`
// A JWT bearer token for client auth (RFC 7523, Sec. 2.2) that will be used // A JWT bearer token for client auth (RFC 7523, Sec. 2.2) that will be used
// to authenticate the AAD SP. Provides more control over token the expiration // to authenticate the AAD SP. Provides more control over token the expiration
// when using certificate authentication than when using `client_cert_path`. // when using certificate authentication than when using `client_cert_path`.
@ -163,6 +165,9 @@ func (c Config) Validate(errs *packersdk.MultiError) {
if _, err := os.Stat(c.ClientCertPath); err != nil { if _, err := os.Stat(c.ClientCertPath); err != nil {
errs = packersdk.MultiErrorAppend(errs, fmt.Errorf("client_cert_path is not an accessible file: %v", err)) errs = packersdk.MultiErrorAppend(errs, fmt.Errorf("client_cert_path is not an accessible file: %v", err))
} }
if c.ClientCertExpireTimeout < 5*time.Minute {
errs = packersdk.MultiErrorAppend(errs, fmt.Errorf("client_cert_token_timeout will expire within 5 minutes, please set a value greater than 5 minutes"))
}
return return
} }
@ -259,7 +264,7 @@ func (c Config) GetServicePrincipalToken(
auth = NewSecretOAuthTokenProvider(*c.cloudEnvironment, c.ClientID, c.ClientSecret, c.TenantID) auth = NewSecretOAuthTokenProvider(*c.cloudEnvironment, c.ClientID, c.ClientSecret, c.TenantID)
case authTypeClientCert: case authTypeClientCert:
say("Getting tokens using client certificate") say("Getting tokens using client certificate")
auth, err = NewCertOAuthTokenProvider(*c.cloudEnvironment, c.ClientID, c.ClientCertPath, c.TenantID) auth, err = NewCertOAuthTokenProvider(*c.cloudEnvironment, c.ClientID, c.ClientCertPath, c.TenantID, c.ClientCertExpireTimeout)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -336,6 +341,10 @@ func (c *Config) FillParameters() error {
c.TenantID = tenantID c.TenantID = tenantID
} }
if c.ClientCertExpireTimeout == 0 {
c.ClientCertExpireTimeout = time.Hour
}
return nil return nil
} }

View File

@ -95,6 +95,16 @@ func Test_ClientConfig_RequiredParametersSet(t *testing.T) {
}, },
wantErr: true, wantErr: true,
}, },
{
name: "client_cert_token_timeout should be 5 minutes or more",
config: Config{
SubscriptionID: "ok",
ClientID: "ok",
ClientCertPath: "/dev/null",
ClientCertExpireTimeout: 1 * time.Minute,
},
wantErr: true,
},
{ {
name: "too many client_* values", name: "too many client_* values",
config: Config{ config: Config{

View File

@ -18,14 +18,14 @@ import (
"github.com/hashicorp/packer/builder/azure/pkcs12" "github.com/hashicorp/packer/builder/azure/pkcs12"
) )
func NewCertOAuthTokenProvider(env azure.Environment, clientID, clientCertPath, tenantID string) (oAuthTokenProvider, error) { func NewCertOAuthTokenProvider(env azure.Environment, clientID, clientCertPath, tenantID string, certExpireTimeout time.Duration) (oAuthTokenProvider, error) {
cert, key, err := readCert(clientCertPath) cert, key, err := readCert(clientCertPath)
if err != nil { if err != nil {
return nil, fmt.Errorf("Error reading certificate: %v", err) return nil, fmt.Errorf("Error reading certificate: %v", err)
} }
audience := fmt.Sprintf("%s%s/oauth2/token", env.ActiveDirectoryEndpoint, tenantID) audience := fmt.Sprintf("%s%s/oauth2/token", env.ActiveDirectoryEndpoint, tenantID)
jwt, err := makeJWT(clientID, audience, cert, key, time.Hour, true) jwt, err := makeJWT(clientID, audience, cert, key, certExpireTimeout, true)
if err != nil { if err != nil {
return nil, fmt.Errorf("Error generating JWT: %v", err) return nil, fmt.Errorf("Error generating JWT: %v", err)
} }

View File

@ -49,6 +49,7 @@ type FlatConfig struct {
ClientID *string `mapstructure:"client_id" cty:"client_id" hcl:"client_id"` ClientID *string `mapstructure:"client_id" cty:"client_id" hcl:"client_id"`
ClientSecret *string `mapstructure:"client_secret" cty:"client_secret" hcl:"client_secret"` ClientSecret *string `mapstructure:"client_secret" cty:"client_secret" hcl:"client_secret"`
ClientCertPath *string `mapstructure:"client_cert_path" cty:"client_cert_path" hcl:"client_cert_path"` ClientCertPath *string `mapstructure:"client_cert_path" cty:"client_cert_path" hcl:"client_cert_path"`
ClientCertExpireTimeout *string `mapstructure:"client_cert_token_timeout" required:"false" cty:"client_cert_token_timeout" hcl:"client_cert_token_timeout"`
ClientJWT *string `mapstructure:"client_jwt" cty:"client_jwt" hcl:"client_jwt"` ClientJWT *string `mapstructure:"client_jwt" cty:"client_jwt" hcl:"client_jwt"`
ObjectID *string `mapstructure:"object_id" cty:"object_id" hcl:"object_id"` ObjectID *string `mapstructure:"object_id" cty:"object_id" hcl:"object_id"`
TenantID *string `mapstructure:"tenant_id" required:"false" cty:"tenant_id" hcl:"tenant_id"` TenantID *string `mapstructure:"tenant_id" required:"false" cty:"tenant_id" hcl:"tenant_id"`
@ -163,6 +164,7 @@ func (*FlatConfig) HCL2Spec() map[string]hcldec.Spec {
"client_id": &hcldec.AttrSpec{Name: "client_id", Type: cty.String, Required: false}, "client_id": &hcldec.AttrSpec{Name: "client_id", Type: cty.String, Required: false},
"client_secret": &hcldec.AttrSpec{Name: "client_secret", Type: cty.String, Required: false}, "client_secret": &hcldec.AttrSpec{Name: "client_secret", Type: cty.String, Required: false},
"client_cert_path": &hcldec.AttrSpec{Name: "client_cert_path", Type: cty.String, Required: false}, "client_cert_path": &hcldec.AttrSpec{Name: "client_cert_path", Type: cty.String, Required: false},
"client_cert_token_timeout": &hcldec.AttrSpec{Name: "client_cert_token_timeout", Type: cty.String, Required: false},
"client_jwt": &hcldec.AttrSpec{Name: "client_jwt", Type: cty.String, Required: false}, "client_jwt": &hcldec.AttrSpec{Name: "client_jwt", Type: cty.String, Required: false},
"object_id": &hcldec.AttrSpec{Name: "object_id", Type: cty.String, Required: false}, "object_id": &hcldec.AttrSpec{Name: "object_id", Type: cty.String, Required: false},
"tenant_id": &hcldec.AttrSpec{Name: "tenant_id", Type: cty.String, Required: false}, "tenant_id": &hcldec.AttrSpec{Name: "tenant_id", Type: cty.String, Required: false},

View File

@ -49,6 +49,7 @@ type FlatConfig struct {
ClientID *string `mapstructure:"client_id" cty:"client_id" hcl:"client_id"` ClientID *string `mapstructure:"client_id" cty:"client_id" hcl:"client_id"`
ClientSecret *string `mapstructure:"client_secret" cty:"client_secret" hcl:"client_secret"` ClientSecret *string `mapstructure:"client_secret" cty:"client_secret" hcl:"client_secret"`
ClientCertPath *string `mapstructure:"client_cert_path" cty:"client_cert_path" hcl:"client_cert_path"` ClientCertPath *string `mapstructure:"client_cert_path" cty:"client_cert_path" hcl:"client_cert_path"`
ClientCertExpireTimeout *string `mapstructure:"client_cert_token_timeout" required:"false" cty:"client_cert_token_timeout" hcl:"client_cert_token_timeout"`
ClientJWT *string `mapstructure:"client_jwt" cty:"client_jwt" hcl:"client_jwt"` ClientJWT *string `mapstructure:"client_jwt" cty:"client_jwt" hcl:"client_jwt"`
ObjectID *string `mapstructure:"object_id" cty:"object_id" hcl:"object_id"` ObjectID *string `mapstructure:"object_id" cty:"object_id" hcl:"object_id"`
TenantID *string `mapstructure:"tenant_id" required:"false" cty:"tenant_id" hcl:"tenant_id"` TenantID *string `mapstructure:"tenant_id" required:"false" cty:"tenant_id" hcl:"tenant_id"`
@ -87,6 +88,7 @@ func (*FlatConfig) HCL2Spec() map[string]hcldec.Spec {
"client_id": &hcldec.AttrSpec{Name: "client_id", Type: cty.String, Required: false}, "client_id": &hcldec.AttrSpec{Name: "client_id", Type: cty.String, Required: false},
"client_secret": &hcldec.AttrSpec{Name: "client_secret", Type: cty.String, Required: false}, "client_secret": &hcldec.AttrSpec{Name: "client_secret", Type: cty.String, Required: false},
"client_cert_path": &hcldec.AttrSpec{Name: "client_cert_path", Type: cty.String, Required: false}, "client_cert_path": &hcldec.AttrSpec{Name: "client_cert_path", Type: cty.String, Required: false},
"client_cert_token_timeout": &hcldec.AttrSpec{Name: "client_cert_token_timeout", Type: cty.String, Required: false},
"client_jwt": &hcldec.AttrSpec{Name: "client_jwt", Type: cty.String, Required: false}, "client_jwt": &hcldec.AttrSpec{Name: "client_jwt", Type: cty.String, Required: false},
"object_id": &hcldec.AttrSpec{Name: "object_id", Type: cty.String, Required: false}, "object_id": &hcldec.AttrSpec{Name: "object_id", Type: cty.String, Required: false},
"tenant_id": &hcldec.AttrSpec{Name: "tenant_id", Type: cty.String, Required: false}, "tenant_id": &hcldec.AttrSpec{Name: "tenant_id", Type: cty.String, Required: false},

View File

@ -61,6 +61,9 @@ you should specify `subscription_id`, `client_id` and one of `client_secret`,
- `client_cert_path` (string) - The location of a PEM file containing a - `client_cert_path` (string) - The location of a PEM file containing a
certificate and private key for service principal. certificate and private key for service principal.
- `client_cert_token_timeout` (duration string | ex: "1h30m12s") - How long to set the expire time on the token created when using
`client_cert_path`.
- `client_jwt` (string) - The bearer JWT assertion signed using a certificate - `client_jwt` (string) - The bearer JWT assertion signed using a certificate
associated with your service principal principal. See [Azure Active associated with your service principal principal. See [Azure Active
Directory docs](https://docs.microsoft.com/en-us/azure/active-directory/develop/active-directory-certificate-credentials) Directory docs](https://docs.microsoft.com/en-us/azure/active-directory/develop/active-directory-certificate-credentials)

View File

@ -94,6 +94,8 @@ way to authenticate the SP to AAD:
for the AAD SP. for the AAD SP.
- `client_cert_path` - allows usage of a certificate to be used to - `client_cert_path` - allows usage of a certificate to be used to
authenticate as the specified AAD SP. authenticate as the specified AAD SP.
- `client_cert_token_timeout` - How long to set the expire time on the token created when using
`client_cert_path`.
- `client_jwt` - For advanced scenario's where the used cannot provide Packer - `client_jwt` - For advanced scenario's where the used cannot provide Packer
the full certificate, they can provide a JWT bearer token for client auth the full certificate, they can provide a JWT bearer token for client auth
(RFC 7523, Sec. 2.2). These bearer tokens are created and signed using a (RFC 7523, Sec. 2.2). These bearer tokens are created and signed using a

View File

@ -12,6 +12,8 @@
- `client_cert_path` (string) - The path to a pem-encoded certificate that will be used to authenticate - `client_cert_path` (string) - The path to a pem-encoded certificate that will be used to authenticate
as the specified AAD SP. as the specified AAD SP.
- `client_cert_token_timeout` (duration string | ex: "1h5m2s") - The timeout for the JWT Token when using a [client certificate](#client_cert_path). Defaults to 1 hour.
- `client_jwt` (string) - A JWT bearer token for client auth (RFC 7523, Sec. 2.2) that will be used - `client_jwt` (string) - A JWT bearer token for client auth (RFC 7523, Sec. 2.2) that will be used
to authenticate the AAD SP. Provides more control over token the expiration to authenticate the AAD SP. Provides more control over token the expiration
when using certificate authentication than when using `client_cert_path`. when using certificate authentication than when using `client_cert_path`.