Skip to content

Commit

Permalink
add credential validation
Browse files Browse the repository at this point in the history
do a pre-flight check of permissions using cloud-credentials-operator validation to do a check on the creds being used for installation

the initial list of permissions that gathers the AWS actions needed to perform an installation are taken verbatim from the IAM group permissions the hive team has been using to perform installation/uninstallation with (there absolutely could be some excess actions that used to be needed, but may no longer be needed)

note that the permissions checks are done with the assumption of IAM policies consisting of 'Resource: "*"'. so a list of ["ec2:CreateRoute", "ec2:CreateSubnet"] is evaluated as whether we can peform

`
{
    "Statement": [
        {
            "Action": [
                "ec2:CreateRoute",
                "ec2:CreateSubnet"
            ],
            "Effect": "Allow",
            "Resource": "*"
        }
    ]
}
`
  • Loading branch information
Joel Diaz committed Feb 4, 2019
1 parent 3d6a665 commit 1dcddc8
Show file tree
Hide file tree
Showing 2 changed files with 226 additions and 3 deletions.
223 changes: 221 additions & 2 deletions pkg/asset/installconfig/aws/permissions.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,225 @@
package aws

import (
_ "github.com/openshift/cloud-credential-operator/pkg/aws"
_ "github.com/openshift/cloud-credential-operator/pkg/controller/utils"
"fmt"

"github.com/aws/aws-sdk-go/aws/session"

"github.com/pkg/errors"
"github.com/sirupsen/logrus"

ccaws "github.com/openshift/cloud-credential-operator/pkg/aws"
credvalidator "github.com/openshift/cloud-credential-operator/pkg/controller/utils"
)

var installPermissions = []string{
// EC2 related perms
"ec2:AllocateAddress",
"ec2:AssociateAddress",
"ec2:AssociateDhcpOptions",
"ec2:AssociateRouteTable",
"ec2:AttachInternetGateway",
"ec2:AuthorizeSecurityGroupEgress",
"ec2:AuthorizeSecurityGroupIngress",
"ec2:CreateDhcpOptions",
"ec2:CreateInternetGateway",
"ec2:CreateNatGateway",
"ec2:CreateRoute",
"ec2:CreateRouteTable",
"ec2:CreateSecurityGroup",
"ec2:CreateSubnet",
"ec2:CreateTags",
"ec2:CreateVpc",
"ec2:CreateVpcEndpoint",
"ec2:CreateVolume",
"ec2:DescribeAccountAttributes",
"ec2:DescribeAddresses",
"ec2:DescribeAvailabilityZones",
"ec2:DescribeDhcpOptions",
"ec2:DescribeImages",
"ec2:DescribeInstanceAttribute",
"ec2:DescribeInstanceCreditSpecifications",
"ec2:DescribeInstances",
"ec2:DescribeInternetGateways",
"ec2:DescribeKeyPairs",
"ec2:DescribeNatGateways",
"ec2:DescribeNetworkAcls",
"ec2:DescribePrefixLists",
"ec2:DescribeRegions",
"ec2:DescribeRouteTables",
"ec2:DescribeSecurityGroups",
"ec2:DescribeSubnets",
"ec2:DescribeTags",
"ec2:DescribeVpcEndpoints",
"ec2:DescribeVpcs",
"ec2:DescribeVpcAttribute",
"ec2:DescribeVolumes",
"ec2:DescribeVpcClassicLink",
"ec2:DescribeVpcClassicLinkDnsSupport",
"ec2:ModifyInstanceAttribute",
"ec2:ModifySubnetAttribute",
"ec2:ModifyVpcAttribute",
"ec2:RevokeSecurityGroupEgress",
"ec2:RunInstances",
"ec2:TerminateInstances",
"ec2:DeleteDhcpOptions",
"ec2:DeleteRoute",
"ec2:RevokeSecurityGroupIngress",
"ec2:DisassociateRouteTable",
"ec2:ReplaceRouteTableAssociation",
"ec2:DeleteRouteTable",
"ec2:DeleteSubnet",
"ec2:DescribeNetworkInterfaces",
"ec2:ModifyNetworkInterfaceAttribute",
"ec2:DeleteNatGateway",
"ec2:DeleteSecurityGroup",
"ec2:DetachInternetGateway",
"ec2:DeleteInternetGateway",
"ec2:ReleaseAddress",
"ec2:DeleteVpc",

// ELB related perms
"elasticloadbalancing:AddTags",
"elasticloadbalancing:ApplySecurityGroupsToLoadBalancer",
"elasticloadbalancing:AttachLoadBalancerToSubnets",
"elasticloadbalancing:CreateListener",
"elasticloadbalancing:CreateLoadBalancer",
"elasticloadbalancing:CreateLoadBalancerListeners",
"elasticloadbalancing:CreateTargetGroup",
"elasticloadbalancing:ConfigureHealthCheck",
"elasticloadbalancing:DeleteLoadBalancer",
"elasticloadbalancing:DeregisterInstancesFromLoadBalancer",
"elasticloadbalancing:DeregisterTargets",
"elasticloadbalancing:DescribeInstanceHealth",
"elasticloadbalancing:DescribeListeners",
"elasticloadbalancing:DescribeLoadBalancers",
"elasticloadbalancing:DescribeLoadBalancerAttributes",
"elasticloadbalancing:DescribeTags",
"elasticloadbalancing:DescribeTargetGroupAttributes",
"elasticloadbalancing:DescribeTargetHealth",
"elasticloadbalancing:ModifyLoadBalancerAttributes",
"elasticloadbalancing:ModifyTargetGroup",
"elasticloadbalancing:ModifyTargetGroupAttributes",
"elasticloadbalancing:RegisterTargets",
"elasticloadbalancing:RegisterInstancesWithLoadBalancer",
"elasticloadbalancing:SetLoadBalancerPoliciesOfListener",

// IAM related perms
"iam:AddRoleToInstanceProfile",
"iam:CreateInstanceProfile",
"iam:CreateRole",
"iam:DeleteInstanceProfile",
"iam:DeleteRole",
"iam:DeleteRolePolicy",
"iam:GetInstanceProfile",
"iam:GetRole",
"iam:GetRolePolicy",
"iam:GetUser",
"iam:PassRole",
"iam:PutRolePolicy",
"iam:RemoveRoleFromInstanceProfile",
"iam:ListInstanceProfilesForRole",
"iam:ListRoles",
"iam:ListUsers",
"iam:SimulatePrincipalPolicy",
"iam:TagRole",

// Route53 related perms
"route53:ChangeResourceRecordSets",
"route53:ChangeTagsForResource",
"route53:GetChange",
"route53:GetHostedZone",
"route53:CreateHostedZone",
"route53:DeleteHostedZone",
"route53:ListHostedZones",
"route53:ListHostedZonesByName",
"route53:ListResourceRecordSets",
"route53:ListTagsForResource",
"route53:UpdateHostedZoneComment",

// S3 related perms
"s3:CreateBucket",
"s3:ListBucket",
"s3:GetBucketCors",
"s3:GetBucketWebsite",
"s3:GetBucketVersioning",
"s3:GetAccelerateConfiguration",
"s3:GetEncryptionConfiguration",
"s3:GetBucketRequestPayment",
"s3:GetBucketLogging",
"s3:GetLifecycleConfiguration",
"s3:GetBucketReplication",
"s3:GetReplicationConfiguration",
"s3:GetBucketLocation",
"s3:GetBucketTagging",
"s3:DeleteBucket",
"s3:PutBucketAcl",
"s3:PutBucketTagging",
"s3:PutEncryptionConfiguration",

// More S3 (would be nice to limit 'Resource' to just the bucket we actualy interact with...)
"s3:PutObject",
"s3:PutObjectAcl",
"s3:PutObjectTagging",
"s3:GetObject",
"s3:GetObjectAcl",
"s3:GetObjectTagging",
"s3:GetObjectVersion",
"s3:DeleteObject",

// Uninstall-specific perms
"autoscaling:DescribeAutoScalingGroups",
"ec2:DeleteNetworkInterface",
"ec2:DeleteVolume",
"ec2:DeleteVpcEndpoints",
"elasticloadbalancing:DescribeTargetGroups",
"elasticloadbalancing:DeleteTargetGroup",
"iam:ListInstanceProfiles",
"iam:ListRolePolicies",
"tag:GetResources",
}

// ValidateCreds will try to create an AWS session, and also verify that the current credentials
// are sufficient to perform an installation, and that they can be used for cluster runtime
// as either capable of creating new credentials for components that interact with the cloud or
// being able to be passed through as-is to the components that need cloud credentials
func ValidateCreds(ssn *session.Session) error {
creds, err := ssn.Config.Credentials.Get()
if err != nil {
return err
}

client, err := ccaws.NewClient([]byte(creds.AccessKeyID), []byte(creds.SecretAccessKey))
if err != nil {
return fmt.Errorf("error building aws client to check credentials against: %v", err)
}

// Check whether we can do an installation
logger := logrus.New()
canInstall, err := credvalidator.CheckPermissionsAgainstActions(client, installPermissions, logger)
if err != nil {
return errors.Errorf("error checking whether we have enough permissions to install: %v", err)
}
if !canInstall {
return errors.New("current credentials insufficient for performing cluster installation")
}

// Check whether we can mint new creds for cluster services needing to interact with the cloud
canMint, err := credvalidator.CheckCloudCredCreation(client, logger)
if err != nil {
return errors.Errorf("error checking whether we can mint new creds with current credentials: %v", err)
}

// Check whether we can use the current credentials in passthrough mode to satisfy
// cluster services needing to interact with the cloud
canPassthrough, err := credvalidator.CheckCloudCredPassthrough(client, logger)
if err != nil {
return errors.Errorf("error checking whether we can use current creds in passthrough mode: %v", err)
}

if !canMint && !canPassthrough {
return errors.New("AWS credentials cannot be used to either create new creds or use as-is")
}

return nil
}
6 changes: 5 additions & 1 deletion pkg/asset/installconfig/platformcredscheck.go
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,11 @@ func (a *PlatformCredsCheck) Generate(dependencies asset.Parents) error {
platform := ic.Config.Platform.Name()
switch platform {
case aws.Name:
_, err = awsconfig.GetSession()
ssn, err := awsconfig.GetSession()
if err != nil {
return err
}
err = awsconfig.ValidateCreds(ssn)
case libvirt.Name:
case none.Name:
case openstack.Name:
Expand Down

0 comments on commit 1dcddc8

Please sign in to comment.