diff --git a/builder/osc/bsu/builder.hcl2spec.go b/builder/osc/bsu/builder.hcl2spec.go index 159749b88..4351186e8 100644 --- a/builder/osc/bsu/builder.hcl2spec.go +++ b/builder/osc/bsu/builder.hcl2spec.go @@ -27,6 +27,8 @@ type FlatConfig struct { SkipValidation *bool `mapstructure:"skip_region_validation" cty:"skip_region_validation" hcl:"skip_region_validation"` SkipMetadataApiCheck *bool `mapstructure:"skip_metadata_api_check" cty:"skip_metadata_api_check" hcl:"skip_metadata_api_check"` Token *string `mapstructure:"token" cty:"token" hcl:"token"` + X509certPath *string `mapstructure:"x509_cert_path" cty:"x509_cert_path" hcl:"x509_cert_path"` + X509keyPath *string `mapstructure:"x509_key_path" cty:"x509_key_path" hcl:"x509_key_path"` OMIName *string `mapstructure:"omi_name" cty:"omi_name" hcl:"omi_name"` OMIDescription *string `mapstructure:"omi_description" cty:"omi_description" hcl:"omi_description"` OMIVirtType *string `mapstructure:"omi_virtualization_type" cty:"omi_virtualization_type" hcl:"omi_virtualization_type"` @@ -150,6 +152,8 @@ func (*FlatConfig) HCL2Spec() map[string]hcldec.Spec { "skip_region_validation": &hcldec.AttrSpec{Name: "skip_region_validation", Type: cty.Bool, Required: false}, "skip_metadata_api_check": &hcldec.AttrSpec{Name: "skip_metadata_api_check", Type: cty.Bool, Required: false}, "token": &hcldec.AttrSpec{Name: "token", Type: cty.String, Required: false}, + "x509_cert_path": &hcldec.AttrSpec{Name: "x509_cert_path", Type: cty.String, Required: false}, + "x509_key_path": &hcldec.AttrSpec{Name: "x509_key_path", Type: cty.String, Required: false}, "omi_name": &hcldec.AttrSpec{Name: "omi_name", Type: cty.String, Required: false}, "omi_description": &hcldec.AttrSpec{Name: "omi_description", Type: cty.String, Required: false}, "omi_virtualization_type": &hcldec.AttrSpec{Name: "omi_virtualization_type", Type: cty.String, Required: false}, diff --git a/builder/osc/bsusurrogate/builder.hcl2spec.go b/builder/osc/bsusurrogate/builder.hcl2spec.go index 3b1fe45c6..e58e67e24 100644 --- a/builder/osc/bsusurrogate/builder.hcl2spec.go +++ b/builder/osc/bsusurrogate/builder.hcl2spec.go @@ -27,6 +27,8 @@ type FlatConfig struct { SkipValidation *bool `mapstructure:"skip_region_validation" cty:"skip_region_validation" hcl:"skip_region_validation"` SkipMetadataApiCheck *bool `mapstructure:"skip_metadata_api_check" cty:"skip_metadata_api_check" hcl:"skip_metadata_api_check"` Token *string `mapstructure:"token" cty:"token" hcl:"token"` + X509certPath *string `mapstructure:"x509_cert_path" cty:"x509_cert_path" hcl:"x509_cert_path"` + X509keyPath *string `mapstructure:"x509_key_path" cty:"x509_key_path" hcl:"x509_key_path"` AssociatePublicIpAddress *bool `mapstructure:"associate_public_ip_address" cty:"associate_public_ip_address" hcl:"associate_public_ip_address"` Subregion *string `mapstructure:"subregion_name" cty:"subregion_name" hcl:"subregion_name"` BlockDurationMinutes *int64 `mapstructure:"block_duration_minutes" cty:"block_duration_minutes" hcl:"block_duration_minutes"` @@ -151,6 +153,8 @@ func (*FlatConfig) HCL2Spec() map[string]hcldec.Spec { "skip_region_validation": &hcldec.AttrSpec{Name: "skip_region_validation", Type: cty.Bool, Required: false}, "skip_metadata_api_check": &hcldec.AttrSpec{Name: "skip_metadata_api_check", Type: cty.Bool, Required: false}, "token": &hcldec.AttrSpec{Name: "token", Type: cty.String, Required: false}, + "x509_cert_path": &hcldec.AttrSpec{Name: "x509_cert_path", Type: cty.String, Required: false}, + "x509_key_path": &hcldec.AttrSpec{Name: "x509_key_path", Type: cty.String, Required: false}, "associate_public_ip_address": &hcldec.AttrSpec{Name: "associate_public_ip_address", Type: cty.Bool, Required: false}, "subregion_name": &hcldec.AttrSpec{Name: "subregion_name", Type: cty.String, Required: false}, "block_duration_minutes": &hcldec.AttrSpec{Name: "block_duration_minutes", Type: cty.Number, Required: false}, diff --git a/builder/osc/bsuvolume/builder.hcl2spec.go b/builder/osc/bsuvolume/builder.hcl2spec.go index df23fbe2a..5adf365d4 100644 --- a/builder/osc/bsuvolume/builder.hcl2spec.go +++ b/builder/osc/bsuvolume/builder.hcl2spec.go @@ -66,6 +66,8 @@ type FlatConfig struct { SkipValidation *bool `mapstructure:"skip_region_validation" cty:"skip_region_validation" hcl:"skip_region_validation"` SkipMetadataApiCheck *bool `mapstructure:"skip_metadata_api_check" cty:"skip_metadata_api_check" hcl:"skip_metadata_api_check"` Token *string `mapstructure:"token" cty:"token" hcl:"token"` + X509certPath *string `mapstructure:"x509_cert_path" cty:"x509_cert_path" hcl:"x509_cert_path"` + X509keyPath *string `mapstructure:"x509_key_path" cty:"x509_key_path" hcl:"x509_key_path"` AssociatePublicIpAddress *bool `mapstructure:"associate_public_ip_address" cty:"associate_public_ip_address" hcl:"associate_public_ip_address"` Subregion *string `mapstructure:"subregion_name" cty:"subregion_name" hcl:"subregion_name"` BlockDurationMinutes *int64 `mapstructure:"block_duration_minutes" cty:"block_duration_minutes" hcl:"block_duration_minutes"` @@ -174,6 +176,8 @@ func (*FlatConfig) HCL2Spec() map[string]hcldec.Spec { "skip_region_validation": &hcldec.AttrSpec{Name: "skip_region_validation", Type: cty.Bool, Required: false}, "skip_metadata_api_check": &hcldec.AttrSpec{Name: "skip_metadata_api_check", Type: cty.Bool, Required: false}, "token": &hcldec.AttrSpec{Name: "token", Type: cty.String, Required: false}, + "x509_cert_path": &hcldec.AttrSpec{Name: "x509_cert_path", Type: cty.String, Required: false}, + "x509_key_path": &hcldec.AttrSpec{Name: "x509_key_path", Type: cty.String, Required: false}, "associate_public_ip_address": &hcldec.AttrSpec{Name: "associate_public_ip_address", Type: cty.Bool, Required: false}, "subregion_name": &hcldec.AttrSpec{Name: "subregion_name", Type: cty.String, Required: false}, "block_duration_minutes": &hcldec.AttrSpec{Name: "block_duration_minutes", Type: cty.Number, Required: false}, diff --git a/builder/osc/chroot/builder.hcl2spec.go b/builder/osc/chroot/builder.hcl2spec.go index d9fc20501..6a40db920 100644 --- a/builder/osc/chroot/builder.hcl2spec.go +++ b/builder/osc/chroot/builder.hcl2spec.go @@ -41,6 +41,8 @@ type FlatConfig struct { SecretKey *string `mapstructure:"secret_key" cty:"secret_key" hcl:"secret_key"` SkipMetadataApiCheck *bool `mapstructure:"skip_metadata_api_check" cty:"skip_metadata_api_check" hcl:"skip_metadata_api_check"` Token *string `mapstructure:"token" cty:"token" hcl:"token"` + X509certPath *string `mapstructure:"x509_cert_path" cty:"x509_cert_path" hcl:"x509_cert_path"` + X509keyPath *string `mapstructure:"x509_key_path" cty:"x509_key_path" hcl:"x509_key_path"` ChrootMounts [][]string `mapstructure:"chroot_mounts" cty:"chroot_mounts" hcl:"chroot_mounts"` CommandWrapper *string `mapstructure:"command_wrapper" cty:"command_wrapper" hcl:"command_wrapper"` CopyFiles []string `mapstructure:"copy_files" cty:"copy_files" hcl:"copy_files"` @@ -103,6 +105,8 @@ func (*FlatConfig) HCL2Spec() map[string]hcldec.Spec { "secret_key": &hcldec.AttrSpec{Name: "secret_key", Type: cty.String, Required: false}, "skip_metadata_api_check": &hcldec.AttrSpec{Name: "skip_metadata_api_check", Type: cty.Bool, Required: false}, "token": &hcldec.AttrSpec{Name: "token", Type: cty.String, Required: false}, + "x509_cert_path": &hcldec.AttrSpec{Name: "x509_cert_path", Type: cty.String, Required: false}, + "x509_key_path": &hcldec.AttrSpec{Name: "x509_key_path", Type: cty.String, Required: false}, "chroot_mounts": &hcldec.AttrSpec{Name: "chroot_mounts", Type: cty.List(cty.List(cty.String)), Required: false}, "command_wrapper": &hcldec.AttrSpec{Name: "command_wrapper", Type: cty.String, Required: false}, "copy_files": &hcldec.AttrSpec{Name: "copy_files", Type: cty.List(cty.String), Required: false}, diff --git a/builder/osc/common/access_config.go b/builder/osc/common/access_config.go index b21b50d61..e02d335c7 100644 --- a/builder/osc/common/access_config.go +++ b/builder/osc/common/access_config.go @@ -23,6 +23,8 @@ type AccessConfig struct { SkipValidation bool `mapstructure:"skip_region_validation"` SkipMetadataApiCheck bool `mapstructure:"skip_metadata_api_check"` Token string `mapstructure:"token"` + X509certPath string `mapstructure:"x509_cert_path"` + X509keyPath string `mapstructure:"x509_key_path"` } // NewOSCClient retrieves the Outscale OSC-SDK client @@ -47,6 +49,14 @@ func (c *AccessConfig) NewOSCClient() *osc.APIClient { c.CustomEndpointOAPI = "outscale.com/oapi/latest" } + if c.X509certPath == "" { + c.X509certPath = os.Getenv("OUTSCALE_X509CERT") + } + + if c.X509keyPath == "" { + c.X509keyPath = os.Getenv("OUTSCALE_X509KEY") + } + return c.NewOSCClientByRegion(c.RawRegion) } @@ -57,11 +67,23 @@ func (c *AccessConfig) GetRegion() string { // NewOSCClientByRegion returns the connection depdending of the region given func (c *AccessConfig) NewOSCClientByRegion(region string) *osc.APIClient { + transport := &http.Transport{ + TLSClientConfig: &tls.Config{InsecureSkipVerify: c.InsecureSkipTLSVerify}, + Proxy: http.ProxyFromEnvironment, + } + + if c.X509certPath != "" && c.X509keyPath != "" { + cert, err := tls.LoadX509KeyPair(c.X509certPath, c.X509keyPath) + if err == nil { + transport.TLSClientConfig = &tls.Config{ + InsecureSkipVerify: c.InsecureSkipTLSVerify, + Certificates: []tls.Certificate{cert}, + } + } + } + skipClient := &http.Client{ - Transport: &http.Transport{ - TLSClientConfig: &tls.Config{InsecureSkipVerify: c.InsecureSkipTLSVerify}, - Proxy: http.ProxyFromEnvironment, - }, + Transport: transport, } skipClient.Transport = NewTransport(c.AccessKey, c.SecretKey, c.RawRegion, skipClient.Transport) diff --git a/website/pages/docs/builders/outscale/index.mdx b/website/pages/docs/builders/outscale/index.mdx index 3a45f409a..365d33c34 100644 --- a/website/pages/docs/builders/outscale/index.mdx +++ b/website/pages/docs/builders/outscale/index.mdx @@ -78,6 +78,33 @@ Usage: $ export OUTSCALE_REGION="eu-west-2" $ packer build packer.json +### x509 Certificate Authentication + +Outscale API now supports x509 Client certificate authentication, in addition of traditional AK/SK HMAC based auth. +This adds an additional layer of security, especially desirable on SecNumCloud compliant regions (cloudgouv-eu-west-1). + +You can set this certificates either by environment variables or by the static credentials inside the packer configuration file. + + +#### Environment variables + +```bash +export OUTSCALE_X509CERT="the/path/to/your/x509cert" +export OUTSCALE_X509KEY="the/path/to/your/x509key" +``` + +#### Static Credentials + +```json +{ + "x509_cert_path": "the/path/to/your/x509cert", + "x509_key_path": "the/path/to/your/x509key", + "region": "cloudgouv-eu-west-1", + "type": "osc-bsu", +} +``` + + ### Checking that system time is current Outscale uses the current time as part of the [request signing