Skip to content

Commit

Permalink
Support usage of IAM role in Kinesis logging endpoint (#255)
Browse files Browse the repository at this point in the history
Adding this support for Kinesis was accidentally left out of the previous commit
claiming to add this support.
  • Loading branch information
kellymclaughlin authored Apr 15, 2021
1 parent 3b3086c commit 7956e5d
Show file tree
Hide file tree
Showing 7 changed files with 125 additions and 17 deletions.
8 changes: 5 additions & 3 deletions pkg/app/run_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -877,19 +877,20 @@ COMMANDS
-n, --name=NAME The name of the S3 logging object
-s, --service-id=SERVICE-ID Service ID
logging kinesis create --name=NAME --version=VERSION --stream-name=STREAM-NAME --access-key=ACCESS-KEY --secret-key=SECRET-KEY --region=REGION [<flags>]
logging kinesis create --name=NAME --version=VERSION --stream-name=STREAM-NAME --region=REGION [<flags>]
Create an Amazon Kinesis logging endpoint on a Fastly service version
-n, --name=NAME The name of the Kinesis logging object. Used
as a primary key for API access
--version=VERSION Number of service version
--stream-name=STREAM-NAME The Amazon Kinesis stream to send logs to
--region=REGION The AWS region where the Kinesis stream
exists
--access-key=ACCESS-KEY The access key associated with the target
Amazon Kinesis stream
--secret-key=SECRET-KEY The secret key associated with the target
Amazon Kinesis stream
--region=REGION The AWS region where the Kinesis stream
exists
--iam-role=IAM-ROLE The IAM role ARN for logging
-s, --service-id=SERVICE-ID Service ID
--format=FORMAT Apache style log formatting
--format-version=FORMAT-VERSION
Expand Down Expand Up @@ -929,6 +930,7 @@ COMMANDS
--stream-name=STREAM-NAME Your Kinesis stream name
--access-key=ACCESS-KEY Your Kinesis account access key
--secret-key=SECRET-KEY Your Kinesis account secret key
--iam-role=IAM-ROLE The IAM role ARN for logging
--region=REGION The AWS region where the Kinesis stream
exists
--format=FORMAT Apache style log formatting
Expand Down
49 changes: 43 additions & 6 deletions pkg/logging/kinesis/create.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package kinesis

import (
"fmt"
"io"

"github.com/fastly/cli/pkg/common"
Expand All @@ -20,10 +21,14 @@ type CreateCommand struct {
EndpointName string // Can't shadow common.Base method Name().
Version int
StreamName string
AccessKey string
SecretKey string
Region string

// mutual exclusions
// AccessKey + SecretKey or IAMRole must be provided
AccessKey common.OptionalString
SecretKey common.OptionalString
IAMRole common.OptionalString

// optional
Format common.OptionalString
FormatVersion common.OptionalUint
Expand All @@ -43,10 +48,13 @@ func NewCreateCommand(parent common.Registerer, globals *config.Data) *CreateCom
c.CmdClause.Flag("name", "The name of the Kinesis logging object. Used as a primary key for API access").Short('n').Required().StringVar(&c.EndpointName)
c.CmdClause.Flag("version", "Number of service version").Required().IntVar(&c.Version)
c.CmdClause.Flag("stream-name", "The Amazon Kinesis stream to send logs to").Required().StringVar(&c.StreamName)
c.CmdClause.Flag("access-key", "The access key associated with the target Amazon Kinesis stream").Required().StringVar(&c.AccessKey)
c.CmdClause.Flag("secret-key", "The secret key associated with the target Amazon Kinesis stream").Required().StringVar(&c.SecretKey)
c.CmdClause.Flag("region", "The AWS region where the Kinesis stream exists").Required().StringVar(&c.Region)

// required, but mutually exclusive
c.CmdClause.Flag("access-key", "The access key associated with the target Amazon Kinesis stream").Action(c.AccessKey.Set).StringVar(&c.AccessKey.Value)
c.CmdClause.Flag("secret-key", "The secret key associated with the target Amazon Kinesis stream").Action(c.SecretKey.Set).StringVar(&c.SecretKey.Value)
c.CmdClause.Flag("iam-role", "The IAM role ARN for logging").Action(c.IAMRole.Set).StringVar(&c.IAMRole.Value)

// optional
c.CmdClause.Flag("service-id", "Service ID").Short('s').StringVar(&c.manifest.Flag.ServiceID)
c.CmdClause.Flag("format", "Apache style log formatting").Action(c.Format.Set).StringVar(&c.Format.Value)
Expand All @@ -70,10 +78,39 @@ func (c *CreateCommand) createInput() (*fastly.CreateKinesisInput, error) {
input.ServiceVersion = c.Version
input.Name = c.EndpointName
input.StreamName = c.StreamName
input.AccessKey = c.AccessKey
input.SecretKey = c.SecretKey
input.Region = c.Region

// The following block checks for invalid permutations of the ways in
// which the AccessKey + SecretKey and IAMRole flags can be
// provided. This is necessary because either the AccessKey and
// SecretKey or the IAMRole is required, but they are mutually
// exclusive. The kingpin library lacks a way to express this constraint
// via the flag specification API so we enforce it manually here.
if !c.AccessKey.WasSet && !c.SecretKey.WasSet && !c.IAMRole.WasSet {
return nil, fmt.Errorf("error parsing arguments: the --access-key and --secret-key flags or the --iam-role flag must be provided")
} else if (c.AccessKey.WasSet || c.SecretKey.WasSet) && c.IAMRole.WasSet {
// Enforce mutual exclusion
return nil, fmt.Errorf("error parsing arguments: the --access-key and --secret-key flags are mutually exclusive with the --iam-role flag")
} else if c.AccessKey.WasSet && !c.SecretKey.WasSet {
return nil, fmt.Errorf("error parsing arguments: required flag --secret-key not provided")

} else if !c.AccessKey.WasSet && c.SecretKey.WasSet {
return nil, fmt.Errorf("error parsing arguments: required flag --access-key not provided")

}

if c.AccessKey.WasSet {
input.AccessKey = c.AccessKey.Value
}

if c.SecretKey.WasSet {
input.SecretKey = c.SecretKey.Value
}

if c.IAMRole.WasSet {
input.IAMRole = c.IAMRole.Value
}

if c.Format.WasSet {
input.Format = c.Format.Value
}
Expand Down
9 changes: 7 additions & 2 deletions pkg/logging/kinesis/describe.go
Original file line number Diff line number Diff line change
Expand Up @@ -49,8 +49,13 @@ func (c *DescribeCommand) Exec(in io.Reader, out io.Writer) error {
fmt.Fprintf(out, "Name: %s\n", kinesis.Name)
fmt.Fprintf(out, "Stream name: %s\n", kinesis.StreamName)
fmt.Fprintf(out, "Region: %s\n", kinesis.Region)
fmt.Fprintf(out, "Access key: %s\n", kinesis.AccessKey)
fmt.Fprintf(out, "Secret key: %s\n", kinesis.SecretKey)
if kinesis.AccessKey != "" || kinesis.SecretKey != "" {
fmt.Fprintf(out, "Access key: %s\n", kinesis.AccessKey)
fmt.Fprintf(out, "Secret key: %s\n", kinesis.SecretKey)
}
if kinesis.IAMRole != "" {
fmt.Fprintf(out, "IAM role: %s\n", kinesis.IAMRole)
}
fmt.Fprintf(out, "Format: %s\n", kinesis.Format)
fmt.Fprintf(out, "Format version: %d\n", kinesis.FormatVersion)
fmt.Fprintf(out, "Response condition: %s\n", kinesis.ResponseCondition)
Expand Down
30 changes: 30 additions & 0 deletions pkg/logging/kinesis/kinesis_integration_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,26 @@ func TestKinesisCreate(t *testing.T) {
args: []string{"logging", "kinesis", "create", "--service-id", "123", "--version", "1", "--name", "log", "--stream-name", "log", "--access-key", "foo", "--region", "us-east-1"},
wantError: "error parsing arguments: required flag --secret-key not provided",
},
{
args: []string{"logging", "kinesis", "create", "--service-id", "123", "--version", "1", "--name", "log", "--stream-name", "log", "--region", "us-east-1", "--access-key", "foo"},
wantError: "error parsing arguments: required flag --secret-key not provided",
},
{
args: []string{"logging", "kinesis", "create", "--service-id", "123", "--version", "1", "--name", "log", "--stream-name", "log", "--region", "us-east-1", "--secret-key", "bar"},
wantError: "error parsing arguments: required flag --access-key not provided",
},
{
args: []string{"logging", "kinesis", "create", "--service-id", "123", "--version", "1", "--name", "log", "--stream-name", "log", "--region", "us-east-1", "--secret-key", "bar", "--iam-role", "arn:aws:iam::123456789012:role/KinesisAccess"},
wantError: "error parsing arguments: the --access-key and --secret-key flags are mutually exclusive with the --iam-role flag",
},
{
args: []string{"logging", "kinesis", "create", "--service-id", "123", "--version", "1", "--name", "log", "--stream-name", "log", "--region", "us-east-1", "--access-key", "foo", "--iam-role", "arn:aws:iam::123456789012:role/KinesisAccess"},
wantError: "error parsing arguments: the --access-key and --secret-key flags are mutually exclusive with the --iam-role flag",
},
{
args: []string{"logging", "kinesis", "create", "--service-id", "123", "--version", "1", "--name", "log", "--stream-name", "log", "--region", "us-east-1", "--access-key", "foo", "--secret-key", "bar", "--iam-role", "arn:aws:iam::123456789012:role/KinesisAccess"},
wantError: "error parsing arguments: the --access-key and --secret-key flags are mutually exclusive with the --iam-role flag",
},
{
args: []string{"logging", "kinesis", "create", "--service-id", "123", "--version", "1", "--name", "log", "--stream-name", "log", "--access-key", "foo", "--secret-key", "bar", "--region", "us-east-1"},
api: mock.API{CreateKinesisFn: createKinesisOK},
Expand All @@ -37,6 +57,16 @@ func TestKinesisCreate(t *testing.T) {
api: mock.API{CreateKinesisFn: createKinesisError},
wantError: errTest.Error(),
},
{
args: []string{"logging", "kinesis", "create", "--service-id", "123", "--version", "1", "--name", "log2", "--stream-name", "log", "--region", "us-east-1", "--iam-role", "arn:aws:iam::123456789012:role/KinesisAccess"},
api: mock.API{CreateKinesisFn: createKinesisOK},
wantOutput: "Created Kinesis logging endpoint log2 (service 123 version 1)",
},
{
args: []string{"logging", "kinesis", "create", "--service-id", "123", "--version", "1", "--name", "log2", "--stream-name", "log", "--region", "us-east-1", "--iam-role", "arn:aws:iam::123456789012:role/KinesisAccess"},
api: mock.API{CreateKinesisFn: createKinesisError},
wantError: errTest.Error(),
},
} {
t.Run(strings.Join(testcase.args, " "), func(t *testing.T) {
var (
Expand Down
31 changes: 27 additions & 4 deletions pkg/logging/kinesis/kinesis_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,17 @@ func TestCreateKinesisInput(t *testing.T) {
SecretKey: "secret",
},
},
{
name: "required values set flag serviceID using IAM role",
cmd: createCommandRequiredIAMRole(),
want: &fastly.CreateKinesisInput{
ServiceID: "123",
ServiceVersion: 2,
Name: "log",
StreamName: "stream",
IAMRole: "arn:aws:iam::123456789012:role/KinesisAccess",
},
},
{
name: "all values set flag serviceID",
cmd: createCommandAll(),
Expand Down Expand Up @@ -93,6 +104,7 @@ func TestUpdateKinesisInput(t *testing.T) {
StreamName: fastly.String("new2"),
AccessKey: fastly.String("new3"),
SecretKey: fastly.String("new4"),
IAMRole: fastly.String(""),
Region: fastly.String("new5"),
Format: fastly.String("new7"),
FormatVersion: fastly.Uint(3),
Expand Down Expand Up @@ -123,8 +135,18 @@ func createCommandRequired() *CreateCommand {
EndpointName: "log",
Version: 2,
StreamName: "stream",
AccessKey: "access",
SecretKey: "secret",
AccessKey: common.OptionalString{Optional: common.Optional{WasSet: true}, Value: "access"},
SecretKey: common.OptionalString{Optional: common.Optional{WasSet: true}, Value: "secret"},
}
}

func createCommandRequiredIAMRole() *CreateCommand {
return &CreateCommand{
manifest: manifest.Data{Flag: manifest.Flag{ServiceID: "123"}},
EndpointName: "log",
Version: 2,
StreamName: "stream",
IAMRole: common.OptionalString{Optional: common.Optional{WasSet: true}, Value: "arn:aws:iam::123456789012:role/KinesisAccess"},
}
}

Expand All @@ -134,8 +156,8 @@ func createCommandAll() *CreateCommand {
EndpointName: "logs",
Version: 2,
StreamName: "stream",
AccessKey: "access",
SecretKey: "secret",
AccessKey: common.OptionalString{Optional: common.Optional{WasSet: true}, Value: "access"},
SecretKey: common.OptionalString{Optional: common.Optional{WasSet: true}, Value: "secret"},
Region: "us-east-1",
Format: common.OptionalString{Optional: common.Optional{WasSet: true}, Value: `%h %l %u %t "%r" %>s %b`},
FormatVersion: common.OptionalUint{Optional: common.Optional{WasSet: true}, Value: 2},
Expand Down Expand Up @@ -169,6 +191,7 @@ func updateCommandAll() *UpdateCommand {
StreamName: common.OptionalString{Optional: common.Optional{WasSet: true}, Value: "new2"},
AccessKey: common.OptionalString{Optional: common.Optional{WasSet: true}, Value: "new3"},
SecretKey: common.OptionalString{Optional: common.Optional{WasSet: true}, Value: "new4"},
IAMRole: common.OptionalString{Optional: common.Optional{WasSet: true}, Value: ""},
Region: common.OptionalString{Optional: common.Optional{WasSet: true}, Value: "new5"},
Format: common.OptionalString{Optional: common.Optional{WasSet: true}, Value: "new7"},
FormatVersion: common.OptionalUint{Optional: common.Optional{WasSet: true}, Value: 3},
Expand Down
9 changes: 7 additions & 2 deletions pkg/logging/kinesis/list.go
Original file line number Diff line number Diff line change
Expand Up @@ -63,8 +63,13 @@ func (c *ListCommand) Exec(in io.Reader, out io.Writer) error {
fmt.Fprintf(out, "\t\tName: %s\n", kinesis.Name)
fmt.Fprintf(out, "\t\tStream name: %s\n", kinesis.StreamName)
fmt.Fprintf(out, "\t\tRegion: %s\n", kinesis.Region)
fmt.Fprintf(out, "\t\tAccess key: %s\n", kinesis.AccessKey)
fmt.Fprintf(out, "\t\tSecret key: %s\n", kinesis.SecretKey)
if kinesis.AccessKey != "" || kinesis.SecretKey != "" {
fmt.Fprintf(out, "\t\tAccess key: %s\n", kinesis.AccessKey)
fmt.Fprintf(out, "\t\tSecret key: %s\n", kinesis.SecretKey)
}
if kinesis.IAMRole != "" {
fmt.Fprintf(out, "\t\tIAM role: %s\n", kinesis.IAMRole)
}
fmt.Fprintf(out, "\t\tFormat: %s\n", kinesis.Format)
fmt.Fprintf(out, "\t\tFormat version: %d\n", kinesis.FormatVersion)
fmt.Fprintf(out, "\t\tResponse condition: %s\n", kinesis.ResponseCondition)
Expand Down
6 changes: 6 additions & 0 deletions pkg/logging/kinesis/update.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ type UpdateCommand struct {
StreamName common.OptionalString
AccessKey common.OptionalString
SecretKey common.OptionalString
IAMRole common.OptionalString
Region common.OptionalString
Format common.OptionalString
FormatVersion common.OptionalUint
Expand All @@ -49,6 +50,7 @@ func NewUpdateCommand(parent common.Registerer, globals *config.Data) *UpdateCom
c.CmdClause.Flag("stream-name", "Your Kinesis stream name").Action(c.StreamName.Set).StringVar(&c.StreamName.Value)
c.CmdClause.Flag("access-key", "Your Kinesis account access key").Action(c.AccessKey.Set).StringVar(&c.AccessKey.Value)
c.CmdClause.Flag("secret-key", "Your Kinesis account secret key").Action(c.SecretKey.Set).StringVar(&c.SecretKey.Value)
c.CmdClause.Flag("iam-role", "The IAM role ARN for logging").Action(c.IAMRole.Set).StringVar(&c.IAMRole.Value)
c.CmdClause.Flag("region", "The AWS region where the Kinesis stream exists").Action(c.Region.Set).StringVar(&c.Region.Value)
c.CmdClause.Flag("format", "Apache style log formatting").Action(c.Format.Set).StringVar(&c.Format.Value)
c.CmdClause.Flag("format-version", "The version of the custom logging format used for the configured endpoint. Can be either 2 (default) or 1").Action(c.FormatVersion.Set).UintVar(&c.FormatVersion.Value)
Expand Down Expand Up @@ -87,6 +89,10 @@ func (c *UpdateCommand) createInput() (*fastly.UpdateKinesisInput, error) {
input.SecretKey = fastly.String(c.SecretKey.Value)
}

if c.IAMRole.WasSet {
input.IAMRole = fastly.String(c.IAMRole.Value)
}

if c.Region.WasSet {
input.Region = fastly.String(c.Region.Value)
}
Expand Down

0 comments on commit 7956e5d

Please sign in to comment.