github.phpd.cn/hashicorp/packer@v1.3.2/builder/amazon/common/step_security_group.go (about) 1 package common 2 3 import ( 4 "context" 5 "fmt" 6 "log" 7 "strings" 8 "time" 9 10 "github.com/aws/aws-sdk-go/aws" 11 "github.com/aws/aws-sdk-go/aws/request" 12 "github.com/aws/aws-sdk-go/service/ec2" 13 "github.com/hashicorp/packer/common/uuid" 14 "github.com/hashicorp/packer/helper/communicator" 15 "github.com/hashicorp/packer/helper/multistep" 16 "github.com/hashicorp/packer/packer" 17 ) 18 19 type StepSecurityGroup struct { 20 CommConfig *communicator.Config 21 SecurityGroupFilter SecurityGroupFilterOptions 22 SecurityGroupIds []string 23 TemporarySGSourceCidr string 24 25 createdGroupId string 26 } 27 28 func (s *StepSecurityGroup) Run(_ context.Context, state multistep.StateBag) multistep.StepAction { 29 ec2conn := state.Get("ec2").(*ec2.EC2) 30 ui := state.Get("ui").(packer.Ui) 31 vpcId := state.Get("vpc_id").(string) 32 33 if len(s.SecurityGroupIds) > 0 { 34 _, err := ec2conn.DescribeSecurityGroups( 35 &ec2.DescribeSecurityGroupsInput{ 36 GroupIds: aws.StringSlice(s.SecurityGroupIds), 37 }, 38 ) 39 if err != nil { 40 err := fmt.Errorf("Couldn't find specified security group: %s", err) 41 log.Printf("[DEBUG] %s", err.Error()) 42 state.Put("error", err) 43 return multistep.ActionHalt 44 } 45 log.Printf("Using specified security groups: %v", s.SecurityGroupIds) 46 state.Put("securityGroupIds", s.SecurityGroupIds) 47 return multistep.ActionContinue 48 } 49 50 if !s.SecurityGroupFilter.Empty() { 51 52 params := &ec2.DescribeSecurityGroupsInput{} 53 if vpcId != "" { 54 s.SecurityGroupFilter.Filters[aws.String("vpc-id")] = &vpcId 55 } 56 params.Filters = buildEc2Filters(s.SecurityGroupFilter.Filters) 57 58 log.Printf("Using SecurityGroup Filters %v", params) 59 60 sgResp, err := ec2conn.DescribeSecurityGroups(params) 61 if err != nil { 62 err := fmt.Errorf("Couldn't find security groups for filter: %s", err) 63 log.Printf("[DEBUG] %s", err.Error()) 64 state.Put("error", err) 65 return multistep.ActionHalt 66 } 67 68 securityGroupIds := []string{} 69 for _, sg := range sgResp.SecurityGroups { 70 securityGroupIds = append(securityGroupIds, *sg.GroupId) 71 } 72 73 ui.Message(fmt.Sprintf("Found Security Group(s): %s", strings.Join(securityGroupIds, ", "))) 74 state.Put("securityGroupIds", securityGroupIds) 75 76 return multistep.ActionContinue 77 } 78 79 port := s.CommConfig.Port() 80 if port == 0 { 81 if s.CommConfig.Type != "none" { 82 panic("port must be set to a non-zero value.") 83 } 84 } 85 86 // Create the group 87 groupName := fmt.Sprintf("packer_%s", uuid.TimeOrderedUUID()) 88 ui.Say(fmt.Sprintf("Creating temporary security group for this instance: %s", groupName)) 89 group := &ec2.CreateSecurityGroupInput{ 90 GroupName: &groupName, 91 Description: aws.String("Temporary group for Packer"), 92 } 93 94 group.VpcId = &vpcId 95 96 groupResp, err := ec2conn.CreateSecurityGroup(group) 97 if err != nil { 98 ui.Error(err.Error()) 99 state.Put("error", err) 100 return multistep.ActionHalt 101 } 102 103 // Set the group ID so we can delete it later 104 s.createdGroupId = *groupResp.GroupId 105 106 // Wait for the security group become available for authorizing 107 log.Printf("[DEBUG] Waiting for temporary security group: %s", s.createdGroupId) 108 err = waitUntilSecurityGroupExists(ec2conn, 109 &ec2.DescribeSecurityGroupsInput{ 110 GroupIds: []*string{aws.String(s.createdGroupId)}, 111 }, 112 ) 113 if err == nil { 114 log.Printf("[DEBUG] Found security group %s", s.createdGroupId) 115 } else { 116 err := fmt.Errorf("Timed out waiting for security group %s: %s", s.createdGroupId, err) 117 log.Printf("[DEBUG] %s", err.Error()) 118 state.Put("error", err) 119 return multistep.ActionHalt 120 } 121 122 // Authorize the SSH access for the security group 123 groupRules := &ec2.AuthorizeSecurityGroupIngressInput{ 124 GroupId: groupResp.GroupId, 125 IpPermissions: []*ec2.IpPermission{ 126 { 127 FromPort: aws.Int64(int64(port)), 128 ToPort: aws.Int64(int64(port)), 129 IpRanges: []*ec2.IpRange{ 130 { 131 CidrIp: aws.String(s.TemporarySGSourceCidr), 132 }, 133 }, 134 IpProtocol: aws.String("tcp"), 135 }, 136 }, 137 } 138 139 ui.Say(fmt.Sprintf( 140 "Authorizing access to port %d from %s in the temporary security group...", 141 port, s.TemporarySGSourceCidr)) 142 _, err = ec2conn.AuthorizeSecurityGroupIngress(groupRules) 143 if err != nil { 144 err := fmt.Errorf("Error authorizing temporary security group: %s", err) 145 state.Put("error", err) 146 ui.Error(err.Error()) 147 return multistep.ActionHalt 148 } 149 150 // Set some state data for use in future steps 151 state.Put("securityGroupIds", []string{s.createdGroupId}) 152 153 return multistep.ActionContinue 154 } 155 156 func (s *StepSecurityGroup) Cleanup(state multistep.StateBag) { 157 if s.createdGroupId == "" { 158 return 159 } 160 161 ec2conn := state.Get("ec2").(*ec2.EC2) 162 ui := state.Get("ui").(packer.Ui) 163 164 ui.Say("Deleting temporary security group...") 165 166 var err error 167 for i := 0; i < 5; i++ { 168 _, err = ec2conn.DeleteSecurityGroup(&ec2.DeleteSecurityGroupInput{GroupId: &s.createdGroupId}) 169 if err == nil { 170 break 171 } 172 173 log.Printf("Error deleting security group: %s", err) 174 time.Sleep(5 * time.Second) 175 } 176 177 if err != nil { 178 ui.Error(fmt.Sprintf( 179 "Error cleaning up security group. Please delete the group manually: %s", s.createdGroupId)) 180 } 181 } 182 183 func waitUntilSecurityGroupExists(c *ec2.EC2, input *ec2.DescribeSecurityGroupsInput) error { 184 ctx := aws.BackgroundContext() 185 w := request.Waiter{ 186 Name: "DescribeSecurityGroups", 187 MaxAttempts: 40, 188 Delay: request.ConstantWaiterDelay(5 * time.Second), 189 Acceptors: []request.WaiterAcceptor{ 190 { 191 State: request.SuccessWaiterState, 192 Matcher: request.PathWaiterMatch, 193 Argument: "length(SecurityGroups[]) > `0`", 194 Expected: true, 195 }, 196 { 197 State: request.RetryWaiterState, 198 Matcher: request.ErrorWaiterMatch, 199 Argument: "", 200 Expected: "InvalidGroup.NotFound", 201 }, 202 { 203 State: request.RetryWaiterState, 204 Matcher: request.ErrorWaiterMatch, 205 Argument: "", 206 Expected: "InvalidSecurityGroupID.NotFound", 207 }, 208 }, 209 Logger: c.Config.Logger, 210 NewRequest: func(opts []request.Option) (*request.Request, error) { 211 var inCpy *ec2.DescribeSecurityGroupsInput 212 if input != nil { 213 tmp := *input 214 inCpy = &tmp 215 } 216 req, _ := c.DescribeSecurityGroupsRequest(inCpy) 217 req.SetContext(ctx) 218 req.ApplyOptions(opts...) 219 return req, nil 220 }, 221 } 222 return w.WaitWithContext(ctx) 223 }