diff --git a/pkg/asset/installconfig/aws/permissions.go b/pkg/asset/installconfig/aws/permissions.go index 4e0b0d1123c..b3b86ce06c3 100644 --- a/pkg/asset/installconfig/aws/permissions.go +++ b/pkg/asset/installconfig/aws/permissions.go @@ -2,6 +2,224 @@ package aws import ( - _ "github.com/openshift/cloud-credential-operator/pkg/aws" - _ "github.com/openshift/cloud-credential-operator/pkg/controller/utils" + "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:ListInstanceProfilesForRole", + "iam:ListRoles", + "iam:ListUsers", + "iam:PassRole", + "iam:PutRolePolicy", + "iam:RemoveRoleFromInstanceProfile", + "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", + "iam:ListUserPolicies", + "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 errors.Wrap(err, "getting creds from session") + } + + client, err := ccaws.NewClient([]byte(creds.AccessKeyID), []byte(creds.SecretAccessKey)) + if err != nil { + return errors.Wrap(err, "initialize cloud-credentials client") + } + + // Check whether we can do an installation + logger := logrus.New() + canInstall, err := credvalidator.CheckPermissionsAgainstActions(client, installPermissions, logger) + if err != nil { + return errors.Wrap(err, "checking install permissions") + } + 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.Wrap(err, "mint credentials check") + } + + // 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.Wrap(err, "passthrough credentials check") + } + + if !canMint && !canPassthrough { + return errors.New("AWS credentials cannot be used to either create new creds or use as-is") + } + + return nil +} diff --git a/pkg/asset/installconfig/platformcredscheck.go b/pkg/asset/installconfig/platformcredscheck.go index 671ae141974..160f96c6f4f 100644 --- a/pkg/asset/installconfig/platformcredscheck.go +++ b/pkg/asset/installconfig/platformcredscheck.go @@ -10,6 +10,7 @@ import ( "github.com/openshift/installer/pkg/types/libvirt" "github.com/openshift/installer/pkg/types/none" "github.com/openshift/installer/pkg/types/openstack" + "github.com/pkg/errors" ) // PlatformCredsCheck is an asset that checks the platform credentials, asks for them or errors out if invalid @@ -35,7 +36,14 @@ 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 errors.Wrap(err, "creating AWS session") + } + err = awsconfig.ValidateCreds(ssn) + if err != nil { + return errors.Wrap(err, "validate AWS credentials") + } case libvirt.Name: case none.Name: case openstack.Name: