ec2

package
v1.1.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Nov 25, 2019 License: Apache-2.0 Imports: 23 Imported by: 0

README

EC2 Plugin

This plugin allows you to create upsreams from groups of EC2 instances.

Sample upstream config

The upstream config below creates an upstream that load balances to all EC2 instances that match the filter spec and are visible to a user with the credentials provided by the secret.

apiVersion: gloo.solo.io/v1
kind: Upstream
metadata:
  annotations:
  name: my-ec2-upstream
  namespace: gloo-system
spec:
  awsEc2:
    filters:
    - key: some-key
    - kvPair:
        key: some-other-key
        value: some-value
    region: us-east-1
    secretRef:
      name: my-aws-secret
      namespace: default

Tutorial: basic use case

  • Below is an outline of how to use the EC2 plugin to create routes to EC2 instances.
  • Assumption: you have gloo installed as a gateway with the EC2 plugin active.

Configure an EC2 instance

  • Provision an EC2 instance

    • Use an "amazon linux" image
    • Configure the security group to allow http traffic on port 80
  • Tag your instance with the following tags

    • gloo-id: abcde123
    • gloo-tag: group1
    • version: v1.2.3
  • Set up your EC2 instance

    • download a demo app: an http response code echo app
      • this app responds to requests with the corresponding response code
        • ex: http:///?code=404 produces a 404 response
    • make the app executable
    • run it in the background
wget https://mitch-solo-public.s3.amazonaws.com/echoapp2
chmod +x echoapp2
sudo ./echoapp2 --port 80 &
  • Verify that you can reach the app
    • curl the app, you should see a help menu for the app
curl http://<instance-public-ip>/

Create a secret with aws credentials

  • Gloo needs AWS credentials to be able to find EC2 resources
  • Recommendation: create a set of credentials that only have access to the relevant resources.
    • In this example, pretend that the secret we create only has access to resources with the gloo-tag:group1 tag.
glooctl create secret aws \
  --name gloo-tag-group1 \
  --namespace default \
  --access-key [aws_secret_key_id] \
  --secret-key [aws_secret_access_key]

Create roles for Gloo to assume on behalf of your upstreams

  • For additional control over Gloo's access to your resources and as an additional filter on your EC2 Upstream's list of available instances it is recommended that you credential your upstreams with a low-access user account that has the ability to assume the specific roles it requires.
  • When you provide both a secret ref and a list of Role ARNs to your upstream, Gloo will call the AWS API with credentials composed from that user account and those roles (via the AssumeRole feature).
  • To configure you AWS account for this use case, there are two steps to take (if you have not already done so):
    • Create a policy that allows the policy holder to describe EC2 instances
    • Create a role that contains that policy and trusts (ie: grants roles assumption to) the upstream's account
Create a role
  • In the AWS console:

    • Navigate to IAM > Roles, choose "Create Role"
    • Follow the interactive guide to create a role
      • Choose "AWS account" as the type of trusted entity and provide the 12 digit account id of the account which holds the EC2 instances you want to route to.
  • Choose or create a policy for the role

    • An example of a Policy that allows the role to describe EC2 instances is shown below.
{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Sid": "VisualEditor0",
            "Effect": "Allow",
            "Action": "ec2:DescribeInstances",
            "Resource": "*"
        }
    ]
}
Allow your upstream's user account to list EC2 instances
  • In the AWS console:
    • Navigate to IAM > Roles, Select your role
    • Select the "Trust relationships" tab
      • Note the entries under the "Trusted entities" table
    • Click "Edit trust relationship"
    • Add your user/service account's ARN to the Principal.AWS list, as shown below
  • An example of Trust Relationship is shown below (many other variants are possible)
    • Add the ARNs of each of the user accounts that you want to allow to assume this role.
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Principal": {
        "AWS": [
          "arn:aws:iam::[account_id]:user/[user_id]"
        ]
      },
      "Action": "sts:AssumeRole"
    }
  ]
}

Create an EC2 Upstream

  • Make an upstream that points to the resources that you want to route to.
  • For this example, we will demonstrate the two ways to build AWS resource filters: by key and by key-value pair.
apiVersion: gloo.solo.io/v1
kind: Upstream
metadata:
  annotations:
  name: ec2-demo-upstream
  namespace: gloo-system
spec:
  awsEc2:
    filters:
    - key: gloo-id
    - kvPair:
        key: gloo-tag
        value: group1
    - kvPair:
        key: version
        value: v1.2.3
    region: us-east-1
    secretRef:
      name: gloo-tag-group1
      namespace: default

Create a route to your upstream

  • Now that you have created an upstream, you can route to it as you would with any other upstream.
glooctl add route  \
  --path-exact /echoapp  \
  --dest-name ec2-demo-upstream \
  --prefix-rewrite /
  • Verify that the route works
    • You should see the same output as when you queried the EC2 instance directly.
export URL=`glooctl proxy url`
curl $URL/echoapp

Potential features, as needed

Discover upstreams

  • The user currently specifies the upstream.
  • Alternatively, the user could just provide credentials, and allow Gloo to discover the specs by inspection of the tags.

Port selection from tag

  • Currently, the port is specified on the upstream spec.
  • It might be useful to allow the user to define the port through a resource tag
  • This would support EC2 upstream discovery
  • What tag to use? Would this be defined on the upstream, a setting, or by a constant?

Notes on configuring user accounts for access to specific instances

  • To restrict your upstream to selecting among specific EC2 instances, you need to give it an AWS secret that has a custom policy which limits its access to specific resources.
  • AWS provides extensive documentation (policy docs, EC2 example), but we will capture the gist here.

Sample custom policy

{
   "Version":"2012-10-17",
   "Statement":[
      {
         "Effect":"Allow",
         "Action":"ec2:DescribeInstances",
         "Resource":[
            "arn:aws:ec2:us-east-1:111122223333:instance/*"
         ],
         "Condition":{
            "StringEquals":{
               "ec2:ResourceTag/Owner":"Gloo"
            }
         }
      }
   ]
}
Action
  • The action that the EC2 upstream credentials must have is ec2:DescribeInstances.
Resource list
  • To restrict an upstream's access to a specific set of instances, list them (wildcards supported) by their Amazon Resource Name (ARN).
  • For EC2, your resource ARN will have this format:
    • arn:aws:ec2:[region]:[account-id]:instance:[resource]:[qualifier]
    • Other variants are possible, refer to the ARN docs for details.
Conditions
  • It is also possible to identify resources by various conditions.
  • The ResourceTags, in particular, are how Gloo chooses which EC2 instances to associate with a given upstream.

Considerations

  • AWS has a highly expressive policy definition protocol for restricting an account's access to resources.
  • Gloo uses the intersection of an upstream's credentials and its filter spec to determine which EC2 instances should be associated with an upstream.
  • You have a few options where to store your config:
    • Permissive upstream credentials (an upstream may be able to list EC2 instances that it should not route to), discerning upstream filters (upstream filters refine the set of target instances)
    • Restrictive upstream credentials (only allow upstream to the credentials that it should route to), no upstream filters
    • Both restrictive upstream credentials and discerning upstream filters (this may serve as a form of documentation or consistency check)

Documentation

Index

Constants

View Source
const DefaultPort = 80
View Source
const InstanceIdAnnotationKey = "instanceId"

Variables

View Source
var (
	CreateSessionFromEnvError = func(err error) error {
		return errors.Wrapf(err, "unable to create a session with credentials taken from env")
	}

	CreateSessionFromSecretError = func(err error) error {
		return errors.Wrapf(err, "unable to create a session with credentials taken from secret ref")
	}
)
View Source
var (
	GetClientError = func(err error) error {
		return errors.Wrapf(err, "unable to get aws client")
	}

	DescribeInstancesError = func(err error) error {
		return errors.Wrapf(err, "unable to describe instances")
	}
)
View Source
var (
	ConstructorInputError = func(factoryType string) error {
		return errors.Errorf("must provide %v factory for EC2 plugin", factoryType)
	}

	ConstructorGetClientError = func(name string, err error) error {
		return errors.Wrapf(err, "unable to get %v client for EC2 plugin", name)
	}

	ConstructorRegisterClientError = func(name string, err error) error {
		return errors.Wrapf(err, "unable to register %v client for EC2 plugin", name)
	}

	WrongUpstreamTypeError = func(upstream *v1.Upstream) error {
		return errors.Errorf("internal error: expected *v1.Upstream_AwsEc2, got %v", reflect.TypeOf(upstream.UpstreamType).Name())
	}

	UpstreamDeltaError = func() error {
		return errors.New("expected no difference between *v1.Upstream_AwsEc2 upstreams")
	}
)

Functions

func GetEc2Client added in v0.17.4

func GetEc2Client(cred *CredentialSpec, secrets v1.SecretList) (*ec2.EC2, error)

func GetInstancesFromDescription added in v0.17.4

func GetInstancesFromDescription(desc *ec2.DescribeInstancesOutput) []*ec2.Instance

func NewEc2InstanceLister

func NewEc2InstanceLister() *ec2InstanceLister

func NewPlugin

func NewPlugin(secretFactory factory.ResourceClientFactory) *plugin

Types

type CredentialKey added in v0.17.4

type CredentialKey struct {
	// contains filtered or unexported fields
}

type CredentialSpec added in v0.17.4

type CredentialSpec struct {
	// contains filtered or unexported fields
}

a credential spec represents an AWS client's view into AWS credentialMap we expect multiple upstreams to share the same view (so we batch the queries and apply filters locally)

func NewCredentialSpecFromEc2UpstreamSpec added in v0.17.4

func NewCredentialSpecFromEc2UpstreamSpec(spec *glooec2.UpstreamSpec) *CredentialSpec

func (*CredentialSpec) Arn added in v0.18.10

func (cs *CredentialSpec) Arn() string

func (*CredentialSpec) Clone added in v0.17.4

func (cs *CredentialSpec) Clone() *CredentialSpec

func (*CredentialSpec) GetKey added in v0.17.4

func (cs *CredentialSpec) GetKey() CredentialKey

func (*CredentialSpec) Region added in v0.17.4

func (cs *CredentialSpec) Region() string

func (*CredentialSpec) SecretRef added in v0.17.4

func (cs *CredentialSpec) SecretRef() *core.ResourceRef

type Ec2InstanceLister added in v0.17.4

type Ec2InstanceLister interface {
	ListForCredentials(ctx context.Context, cred *CredentialSpec, secrets v1.SecretList) ([]*ec2.Instance, error)
}

Ec2InstanceLister is a simple interface for calling the AWS API. This allows us to easily mock the API in our tests.

type FilterMap added in v0.17.4

type FilterMap map[string]string

a FilterMap is created for each EC2 instance so we can efficiently filter the instances associated with a given upstream's filter spec filter maps are generated from tag lists, the keys are the tag keys, the values are the tag values

Directories

Path Synopsis

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL