github.com/coreos/mantle@v0.13.0/platform/api/aws/iam.go (about)

     1  // Copyright 2017 CoreOS, Inc.
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //     http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  package aws
    16  
    17  import (
    18  	"fmt"
    19  	"time"
    20  
    21  	"github.com/aws/aws-sdk-go/aws"
    22  	"github.com/aws/aws-sdk-go/aws/awserr"
    23  	"github.com/aws/aws-sdk-go/service/iam"
    24  
    25  	"github.com/coreos/mantle/util"
    26  )
    27  
    28  const (
    29  	ec2AssumeRolePolicy = `{
    30    "Version": "2012-10-17",
    31    "Statement": [
    32      {
    33        "Sid": "",
    34        "Effect": "Allow",
    35        "Principal": {
    36          "Service": "ec2.amazonaws.com"
    37        },
    38        "Action": "sts:AssumeRole"
    39      }
    40    ]
    41  }`
    42  	s3ReadOnlyAccess = `{
    43      "Version": "2012-10-17",
    44      "Statement": [
    45          {
    46              "Effect": "Allow",
    47              "Action": [
    48                  "s3:Get*",
    49                  "s3:List*"
    50              ],
    51              "Resource": "*"
    52          }
    53      ]
    54  }`
    55  )
    56  
    57  // ensureInstanceProfile checks that the specified instance profile exists,
    58  // and creates it and its backing role if not. The role will have the
    59  // AmazonS3RReadOnlyAccess permissions policy applied to allow fetches
    60  // of S3 objects that are not owned by the root account.
    61  func (a *API) ensureInstanceProfile(name string) error {
    62  	_, err := a.iam.GetInstanceProfile(&iam.GetInstanceProfileInput{
    63  		InstanceProfileName: &name,
    64  	})
    65  	if err == nil {
    66  		return nil
    67  	}
    68  	if awserr, ok := err.(awserr.Error); !ok || awserr.Code() != "NoSuchEntity" {
    69  		return fmt.Errorf("getting instance profile %q: %v", name, err)
    70  	}
    71  
    72  	_, err = a.iam.CreateRole(&iam.CreateRoleInput{
    73  		RoleName:                 &name,
    74  		Description:              aws.String("mantle role for testing"),
    75  		AssumeRolePolicyDocument: aws.String(ec2AssumeRolePolicy),
    76  	})
    77  	if err != nil {
    78  		return fmt.Errorf("creating role %q: %v", name, err)
    79  	}
    80  	policy := "AmazonS3ReadOnlyAccess"
    81  	_, err = a.iam.PutRolePolicy(&iam.PutRolePolicyInput{
    82  		PolicyName:     &policy,
    83  		PolicyDocument: aws.String(s3ReadOnlyAccess),
    84  		RoleName:       &name,
    85  	})
    86  	if err != nil {
    87  		return fmt.Errorf("adding %q policy to role %q: %v", policy, name, err)
    88  	}
    89  
    90  	_, err = a.iam.CreateInstanceProfile(&iam.CreateInstanceProfileInput{
    91  		InstanceProfileName: &name,
    92  	})
    93  	if err != nil {
    94  		return fmt.Errorf("creating instance profile %q: %v", name, err)
    95  	}
    96  
    97  	_, err = a.iam.AddRoleToInstanceProfile(&iam.AddRoleToInstanceProfileInput{
    98  		InstanceProfileName: &name,
    99  		RoleName:            &name,
   100  	})
   101  	if err != nil {
   102  		return fmt.Errorf("adding role %q to instance profile %q: %v", name, name, err)
   103  	}
   104  
   105  	// wait for instance profile to fully exist in IAM before returning.
   106  	// note that this does not guarantee that it will exist within ec2.
   107  	err = util.WaitUntilReady(30*time.Second, 5*time.Second, func() (bool, error) {
   108  		_, err = a.iam.GetInstanceProfile(&iam.GetInstanceProfileInput{
   109  			InstanceProfileName: &name,
   110  		})
   111  		if err != nil {
   112  			return false, nil
   113  		}
   114  		return true, nil
   115  	})
   116  	if err != nil {
   117  		return fmt.Errorf("waiting for instance profile to become ready: %v", err)
   118  	}
   119  
   120  	return nil
   121  }