diff --git a/CHANGELOG.md b/CHANGELOG.md index 7817d2f56..1bcdc79b0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,9 +10,12 @@ ### Enhancements: +- feat(service/backend): Add support for IAM authentication ([#1963](https://github.com/fastly/cli/pull/1963)) + ### Dependencies: - build(deps): `github.com/fastly/go-fastly` from v18.1.0 to v19.0.0 +- build(deps): `github.com/fastly/go-fastly` from v19.0.0 to v19.1.0 ([#1963](https://github.com/fastly/cli/pull/1963)) ## [v17.0.0](https://github.com/fastly/cli/releases/tag/v17.0.0) (2026-10-26) diff --git a/go.mod b/go.mod index 4d07686dd..7084cbb18 100644 --- a/go.mod +++ b/go.mod @@ -85,7 +85,7 @@ require ( require ( 4d63.com/optional v0.2.0 github.com/creack/pty v1.1.24 - github.com/fastly/go-fastly/v19 v19.0.0 + github.com/fastly/go-fastly/v19 v19.1.0 github.com/mholt/archives v0.1.5 github.com/mitchellh/go-ps v1.0.0 ) diff --git a/go.sum b/go.sum index 155174635..e48e32c5b 100644 --- a/go.sum +++ b/go.sum @@ -34,8 +34,8 @@ github.com/dsnet/compress v0.0.2-0.20230904184137-39efe44ab707/go.mod h1:qssHWj6 github.com/dsnet/golib v0.0.0-20171103203638-1ea166775780/go.mod h1:Lj+Z9rebOhdfkVLjJ8T6VcRQv3SXugXy999NBtR9aFY= github.com/dustinkirkland/golang-petname v0.0.0-20240428194347-eebcea082ee0 h1:aYo8nnk3ojoQkP5iErif5Xxv0Mo0Ga/FR5+ffl/7+Nk= github.com/dustinkirkland/golang-petname v0.0.0-20240428194347-eebcea082ee0/go.mod h1:8AuBTZBRSFqEYBPYULd+NN474/zZBLP+6WeT5S9xlAc= -github.com/fastly/go-fastly/v19 v19.0.0 h1:v999BACPkX/VK+YvqnPFPTPAu/LwWn9kBDCSlA20Sa4= -github.com/fastly/go-fastly/v19 v19.0.0/go.mod h1:Qjg+2rTkEsDQ67N3evO3qyUuAa2VY/sOAcyIONqU7HE= +github.com/fastly/go-fastly/v19 v19.1.0 h1:+9LqAZOyl/0Z/AAQvngW2sq1FMGM/VebmMNX5Eo4DPI= +github.com/fastly/go-fastly/v19 v19.1.0/go.mod h1:R3gDLScUFu2BX9nHDr3cD6Czok/B+NeTAHRrmxOLHaw= github.com/fastly/kingpin v2.1.12-0.20191105091915-95d230a53780+incompatible h1:FhrXlfhgGCS+uc6YwyiFUt04alnjpoX7vgDKJxS6Qbk= github.com/fastly/kingpin v2.1.12-0.20191105091915-95d230a53780+incompatible/go.mod h1:U8UynVoU1SQaqD2I4ZqgYd5lx3A1ipQYn4aSt2Y5h6c= github.com/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYFFOfk= diff --git a/pkg/commands/service/backend/backend_test.go b/pkg/commands/service/backend/backend_test.go index 6586e7ab2..73082e95b 100644 --- a/pkg/commands/service/backend/backend_test.go +++ b/pkg/commands/service/backend/backend_test.go @@ -617,6 +617,11 @@ var listBackendsJSONOutput = strings.TrimSpace(` "FirstByteTimeout": null, "HealthCheck": null, "Hostname": null, + "IAMExternalID": null, + "IAMProduct": null, + "IAMRegion": null, + "IAMRole": null, + "IAMVendor": null, "KeepAliveTime": null, "MaxConn": null, "MaxUse": null, @@ -659,6 +664,11 @@ var listBackendsJSONOutput = strings.TrimSpace(` "FirstByteTimeout": null, "HealthCheck": null, "Hostname": null, + "IAMExternalID": null, + "IAMProduct": null, + "IAMRegion": null, + "IAMRole": null, + "IAMVendor": null, "KeepAliveTime": null, "MaxConn": null, "MaxUse": null, @@ -736,6 +746,11 @@ var listBackendsVerboseOutput = strings.Join([]string{ " TCP KeepAlive Interval: 0", " TCP KeepAlive Probes: 0", " TCP KeepAlive Timeout: 0", + " IAM External ID: ", + " IAM Product: ", + " IAM Region: ", + " IAM Role: ", + " IAM Vendor: ", " Backend 2/2", " Name: example.com", " Comment: example", @@ -767,6 +782,11 @@ var listBackendsVerboseOutput = strings.Join([]string{ " TCP KeepAlive Interval: 0", " TCP KeepAlive Probes: 0", " TCP KeepAlive Timeout: 0", + " IAM External ID: ", + " IAM Product: ", + " IAM Region: ", + " IAM Role: ", + " IAM Vendor: ", }, "\n") + "\n\n" func getBackendOK(_ context.Context, i *fastly.GetBackendInput) (*fastly.Backend, error) { diff --git a/pkg/commands/service/backend/create.go b/pkg/commands/service/backend/create.go index 236ff532d..9fd8752aa 100644 --- a/pkg/commands/service/backend/create.go +++ b/pkg/commands/service/backend/create.go @@ -31,6 +31,11 @@ type CreateCommand struct { connectTimeout argparser.OptionalInt firstByteTimeout argparser.OptionalInt healthCheck argparser.OptionalString + iamExternalID argparser.OptionalString + iamProduct argparser.OptionalString + iamRegion argparser.OptionalString + iamRole argparser.OptionalString + iamVendor argparser.OptionalString maxConn argparser.OptionalInt maxUse argparser.OptionalInt maxLifetime argparser.OptionalInt @@ -90,6 +95,11 @@ func NewCreateCommand(parent argparser.Registerer, g *global.Data) *CreateComman c.CmdClause.Flag("connect-timeout", "How long to wait for a timeout in milliseconds").Action(c.connectTimeout.Set).IntVar(&c.connectTimeout.Value) c.CmdClause.Flag("first-byte-timeout", "How long to wait for the first bytes in milliseconds").Action(c.firstByteTimeout.Set).IntVar(&c.firstByteTimeout.Value) c.CmdClause.Flag("healthcheck", "The name of the healthcheck to use with this backend").Action(c.healthCheck.Set).StringVar(&c.healthCheck.Value) + c.CmdClause.Flag("iam-external-id", "If the backend is using IAM authentication and the IAM system policy requires a matching external identifier, it should match this value (your Fastly customer ID will be used if this is not set)").Action(c.iamExternalID.Set).StringVar(&c.iamExternalID.Value) + c.CmdClause.Flag("iam-product", "If the backend is using IAM authentication, the IAM signature will use this as the product element").Action(c.iamProduct.Set).StringVar(&c.iamProduct.Value) + c.CmdClause.Flag("iam-region", "If the backend is using IAM authentication, this region will be used for signing and access").Action(c.iamRegion.Set).StringVar(&c.iamRegion.Value) + c.CmdClause.Flag("iam-role", "If the backend is using IAM authentication, the fully qualified role string supplied by the storage vendor").Action(c.iamRole.Set).StringVar(&c.iamRole.Value) + c.CmdClause.Flag("iam-vendor", "A label that identifies the storage vendor. Providing a value enables IAM usage").Action(c.iamVendor.Set).StringVar(&c.iamVendor.Value) c.CmdClause.Flag("max-conn", "Maximum number of connections").Action(c.maxConn.Set).IntVar(&c.maxConn.Value) c.CmdClause.Flag("max-use", "Maximum number of requests allowed over a single, pooled HTTP keepalive connection to this backend; 0 is treated as unlimited.").Action(c.maxUse.Set).IntVar(&c.maxUse.Value) c.CmdClause.Flag("max-lifetime", "Maximum time from creation (in milliseconds) that a pooled HTTP keepalive connection will be eligible for reuse; 0 is treated as unlimited.").Action(c.maxLifetime.Set).IntVar(&c.maxLifetime.Value) @@ -293,6 +303,22 @@ func (c *CreateCommand) Exec(_ io.Reader, out io.Writer) error { } } + if c.iamExternalID.WasSet { + input.IAMExternalID = &c.iamExternalID.Value + } + if c.iamProduct.WasSet { + input.IAMProduct = &c.iamProduct.Value + } + if c.iamRegion.WasSet { + input.IAMRegion = &c.iamRegion.Value + } + if c.iamRole.WasSet { + input.IAMRole = &c.iamRole.Value + } + if c.iamVendor.WasSet { + input.IAMVendor = &c.iamVendor.Value + } + b, err := c.Globals.APIClient.CreateBackend(context.TODO(), &input) if err != nil { c.Globals.ErrLog.AddWithContext(err, map[string]any{ diff --git a/pkg/commands/service/backend/describe.go b/pkg/commands/service/backend/describe.go index 18f671761..abd5404cc 100644 --- a/pkg/commands/service/backend/describe.go +++ b/pkg/commands/service/backend/describe.go @@ -139,6 +139,11 @@ func (c *DescribeCommand) print(out io.Writer, b *fastly.Backend) error { fmt.Fprintf(out, "TCP KeepAlive Interval: %v\n", fastly.ToValue(b.TCPKeepAliveIntvl)) fmt.Fprintf(out, "TCP KeepAlive Probes: %v\n", fastly.ToValue(b.TCPKeepAliveProbes)) fmt.Fprintf(out, "TCP KeepAlive Timeout: %v\n", fastly.ToValue(b.TCPKeepAliveTime)) + fmt.Fprintf(out, "IAM External ID: %v\n", fastly.ToValue(b.IAMExternalID)) + fmt.Fprintf(out, "IAM Product: %v\n", fastly.ToValue(b.IAMProduct)) + fmt.Fprintf(out, "IAM Region: %v\n", fastly.ToValue(b.IAMRegion)) + fmt.Fprintf(out, "IAM Role: %v\n", fastly.ToValue(b.IAMRole)) + fmt.Fprintf(out, "IAM Vendor: %v\n", fastly.ToValue(b.IAMVendor)) return nil } diff --git a/pkg/commands/service/backend/update.go b/pkg/commands/service/backend/update.go index 794d79cfe..8a5c68576 100644 --- a/pkg/commands/service/backend/update.go +++ b/pkg/commands/service/backend/update.go @@ -30,6 +30,11 @@ type UpdateCommand struct { FirstByteTimeout argparser.OptionalInt HealthCheck argparser.OptionalString Hostname argparser.OptionalString + iamExternalID argparser.OptionalString + iamProduct argparser.OptionalString + iamRegion argparser.OptionalString + iamRole argparser.OptionalString + iamVendor argparser.OptionalString MaxConn argparser.OptionalInt MaxUse argparser.OptionalInt MaxLifetime argparser.OptionalInt @@ -88,6 +93,11 @@ func NewUpdateCommand(parent argparser.Registerer, g *global.Data) *UpdateComman c.CmdClause.Flag("connect-timeout", "How long to wait for a timeout in milliseconds").Action(c.ConnectTimeout.Set).IntVar(&c.ConnectTimeout.Value) c.CmdClause.Flag("first-byte-timeout", "How long to wait for the first bytes in milliseconds").Action(c.FirstByteTimeout.Set).IntVar(&c.FirstByteTimeout.Value) c.CmdClause.Flag("healthcheck", "The name of the healthcheck to use with this backend").Action(c.HealthCheck.Set).StringVar(&c.HealthCheck.Value) + c.CmdClause.Flag("iam-external-id", "If the backend is using IAM authentication and the IAM system policy requires a matching external identifier, it should match this value (your Fastly customer ID will be used if this is not set)").Action(c.iamExternalID.Set).StringVar(&c.iamExternalID.Value) + c.CmdClause.Flag("iam-product", "If the backend is using IAM authentication, the IAM signature will use this as the product element").Action(c.iamProduct.Set).StringVar(&c.iamProduct.Value) + c.CmdClause.Flag("iam-region", "If the backend is using IAM authentication, this region will be used for signing and access").Action(c.iamRegion.Set).StringVar(&c.iamRegion.Value) + c.CmdClause.Flag("iam-role", "If the backend is using IAM authentication, the fully qualified role string supplied by the storage vendor").Action(c.iamRole.Set).StringVar(&c.iamRole.Value) + c.CmdClause.Flag("iam-vendor", "A label that identifies the storage vendor. Providing a value enables IAM usage").Action(c.iamVendor.Set).StringVar(&c.iamVendor.Value) c.CmdClause.Flag("max-conn", "Maximum number of connections").Action(c.MaxConn.Set).IntVar(&c.MaxConn.Value) c.CmdClause.Flag("max-use", "Maximum number of requests allowed over a single, pooled HTTP keepalive connection to this backend; 0 is treated as unlimited.").Action(c.MaxUse.Set).IntVar(&c.MaxUse.Value) c.CmdClause.Flag("max-lifetime", "Maximum time from creation (in milliseconds) that a pooled HTTP keepalive connection will be eligible for reuse; 0 is treated as unlimited.").Action(c.MaxLifetime.Set).IntVar(&c.MaxLifetime.Value) @@ -295,6 +305,22 @@ func (c *UpdateCommand) Exec(_ io.Reader, out io.Writer) error { input.KeepAliveTime = &c.HTTPKaTime.Value } + if c.iamExternalID.WasSet { + input.IAMExternalID = &c.iamExternalID.Value + } + if c.iamProduct.WasSet { + input.IAMProduct = &c.iamProduct.Value + } + if c.iamRegion.WasSet { + input.IAMRegion = &c.iamRegion.Value + } + if c.iamRole.WasSet { + input.IAMRole = &c.iamRole.Value + } + if c.iamVendor.WasSet { + input.IAMVendor = &c.iamVendor.Value + } + b, err := c.Globals.APIClient.UpdateBackend(context.TODO(), input) if err != nil { c.Globals.ErrLog.AddWithContext(err, map[string]any{ diff --git a/pkg/text/backend.go b/pkg/text/backend.go index d0af9d5d6..ba9538559 100644 --- a/pkg/text/backend.go +++ b/pkg/text/backend.go @@ -49,4 +49,9 @@ func PrintBackend(out io.Writer, prefix string, b *fastly.Backend) { fmt.Fprintf(out, "TCP KeepAlive Interval: %v\n", fastly.ToValue(b.TCPKeepAliveIntvl)) fmt.Fprintf(out, "TCP KeepAlive Probes: %v\n", fastly.ToValue(b.TCPKeepAliveProbes)) fmt.Fprintf(out, "TCP KeepAlive Timeout: %v\n", fastly.ToValue(b.TCPKeepAliveTime)) + fmt.Fprintf(out, "IAM External ID: %v\n", fastly.ToValue(b.IAMExternalID)) + fmt.Fprintf(out, "IAM Product: %v\n", fastly.ToValue(b.IAMProduct)) + fmt.Fprintf(out, "IAM Region: %v\n", fastly.ToValue(b.IAMRegion)) + fmt.Fprintf(out, "IAM Role: %v\n", fastly.ToValue(b.IAMRole)) + fmt.Fprintf(out, "IAM Vendor: %v\n", fastly.ToValue(b.IAMVendor)) }