Skip to content

Commit

Permalink
delete security groups endpoint
Browse files Browse the repository at this point in the history
  • Loading branch information
fishnix committed Sep 13, 2021
1 parent 7aeeb91 commit f8698b8
Show file tree
Hide file tree
Showing 12 changed files with 243 additions and 439 deletions.
43 changes: 41 additions & 2 deletions api/handlers_sgs.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,12 @@ package api

import (
"fmt"
"net/http"
"strconv"

"github.com/YaleSpinup/apierror"
"github.com/YaleSpinup/ec2-api/ec2"
"github.com/gorilla/mux"
"net/http"
"strconv"
)

func (s *server) SecurityGroupListHandler(w http.ResponseWriter, r *http.Request) {
Expand Down Expand Up @@ -89,3 +90,41 @@ func (s *server) SecurityGroupGetHandler(w http.ResponseWriter, r *http.Request)

handleResponseOk(w, toEc2SecurityGroupResponse(out[0]))
}

func (s *server) SecurityGroupDeleteHandler(w http.ResponseWriter, r *http.Request) {
w = LogWriter{w}
vars := mux.Vars(r)
account := s.mapAccountNumber(vars["account"])
id := vars["id"]

role := fmt.Sprintf("arn:aws:iam::%s:role/%s", account, s.session.RoleName)
policy, err := sgDeletePolicy(id)
if err != nil {
handleError(w, apierror.New(apierror.ErrInternalError, "failed to generate policy", err))
return
}

session, err := s.assumeRole(
r.Context(),
s.session.ExternalID,
role,
policy,
)
if err != nil {
msg := fmt.Sprintf("failed to assume role in account: %s", account)
handleError(w, apierror.New(apierror.ErrForbidden, msg, err))
return
}

service := ec2.New(
ec2.WithSession(session.Session),
ec2.WithOrg(s.org),
)

if err := service.DeleteSecurityGroup(r.Context(), id); err != nil {
handleError(w, err)
return
}

handleResponseOk(w, "OK")
}
64 changes: 64 additions & 0 deletions api/policy.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
package api

import (
"encoding/json"
"fmt"

"github.com/YaleSpinup/aws-go/services/iam"

log "github.com/sirupsen/logrus"
)

// orgTagAccessPolicy generates the org tag conditional policy to be passed inline when assuming a role
func orgTagAccessPolicy(org string) (string, error) {
log.Debugf("generating org policy document")

policy := iam.PolicyDocument{
Version: "2012-10-17",
Statement: []iam.StatementEntry{
{
Effect: "Allow",
Action: []string{"*"},
Resource: []string{"*"},
Condition: iam.Condition{
"StringEquals": iam.ConditionStatement{
"aws:ResourceTag/spinup:org": []string{org},
},
},
},
},
}

j, err := json.Marshal(policy)
if err != nil {
return "", err
}

return string(j), nil
}

func sgDeletePolicy(id string) (string, error) {
log.Debugf("generating org policy document")

sgResource := fmt.Sprintf("arn:aws:ec2:*:*:security-group/%s", id)

policy := iam.PolicyDocument{
Version: "2012-10-17",
Statement: []iam.StatementEntry{
{
Effect: "Allow",
Action: []string{
"ec2:DeleteSecurityGroup",
},
Resource: []string{sgResource},
},
},
}

j, err := json.Marshal(policy)
if err != nil {
return "", err
}

return string(j), nil
}
2 changes: 1 addition & 1 deletion api/routes.go
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@ func (s *server) routes() {
api.HandleFunc("/{account}/instances/{id}", s.ProxyRequestHandler).Methods(http.MethodDelete)
api.HandleFunc("/{account}/instances/{id}/volumes/{vid}", s.ProxyRequestHandler).Methods(http.MethodDelete)
api.HandleFunc("/{account}/instanceprofiles/{name}", s.ProxyRequestHandler).Methods(http.MethodDelete)
api.HandleFunc("/{account}/sgs/{id}", s.ProxyRequestHandler).Methods(http.MethodDelete)
api.HandleFunc("/{account}/sgs/{id}", s.SecurityGroupDeleteHandler).Methods(http.MethodDelete)
api.HandleFunc("/{account}/volumes/{id}", s.ProxyRequestHandler).Methods(http.MethodDelete)
api.HandleFunc("/{account}/snapshots/{id}", s.ProxyRequestHandler).Methods(http.MethodDelete)
api.HandleFunc("/{account}/images/{id}", s.ProxyRequestHandler).Methods(http.MethodDelete)
Expand Down
30 changes: 0 additions & 30 deletions api/server.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,15 +18,13 @@ package api

import (
"context"
"encoding/json"
"errors"
"math/rand"
"net/http"
"os"
"time"

"github.com/YaleSpinup/ec2-api/common"
"github.com/YaleSpinup/ec2-api/iam"
"github.com/YaleSpinup/ec2-api/session"
"github.com/gorilla/handlers"
"github.com/gorilla/mux"
Expand Down Expand Up @@ -217,34 +215,6 @@ func retry(attempts int, sleep time.Duration, f func() error) error {
return nil
}

// orgTagAccessPolicy generates the org tag conditional policy to be passed inline when assuming a role
func orgTagAccessPolicy(org string) (string, error) {
log.Debugf("generating org policy document")

policy := iam.PolicyDocument{
Version: "2012-10-17",
Statement: []iam.StatementEntry{
{
Effect: "Allow",
Action: []string{"*"},
Resource: "*",
Condition: iam.Condition{
"StringEquals": iam.ConditionStatement{
"aws:ResourceTag/spinup:org": org,
},
},
},
},
}

j, err := json.Marshal(policy)
if err != nil {
return "", err
}

return string(j), nil
}

// if we have an entry for the account name, return the associated account number
func (s *server) mapAccountNumber(name string) string {
if a, ok := s.accountsMap[name]; ok {
Expand Down
18 changes: 18 additions & 0 deletions ec2/sgs.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package ec2

import (
"context"

"github.com/YaleSpinup/apierror"
"github.com/aws/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go/service/ec2"
Expand Down Expand Up @@ -66,3 +67,20 @@ func (e *Ec2) GetSecurityGroup(ctx context.Context, ids ...string) ([]*ec2.Secur

return out.SecurityGroups, err
}

// DeleteSecurityGroup deletes the given security group
func (e *Ec2) DeleteSecurityGroup(ctx context.Context, id string) error {
if id == "" {
return apierror.New(apierror.ErrBadRequest, "invalid input", nil)
}

log.Infof("deleting security group %s", id)

if _, err := e.Service.DeleteSecurityGroupWithContext(ctx, &ec2.DeleteSecurityGroupInput{
GroupId: aws.String(id),
}); err != nil {
return ErrCode("deleting security group", err)
}

return nil
}
112 changes: 110 additions & 2 deletions ec2/sgs_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,15 @@ package ec2

import (
"context"
"reflect"
"testing"

"github.com/aws/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go/aws/awserr"
"github.com/aws/aws-sdk-go/aws/request"
"github.com/aws/aws-sdk-go/aws/session"
"github.com/aws/aws-sdk-go/service/ec2"
"github.com/aws/aws-sdk-go/service/ec2/ec2iface"
"reflect"
"testing"
)

var securityGroups = []*ec2.SecurityGroup{
Expand Down Expand Up @@ -328,6 +330,20 @@ func (m mockEC2Client) DescribeSecurityGroupsWithContext(ctx context.Context, in
return &ec2.DescribeSecurityGroupsOutput{SecurityGroups: securityGroupList}, nil
}

func (m mockEC2Client) DeleteSecurityGroupWithContext(ctx context.Context, input *ec2.DeleteSecurityGroupInput, opts ...request.Option) (*ec2.DeleteSecurityGroupOutput, error) {
if m.err != nil {
return nil, m.err
}

for _, securityGroup := range securityGroups {
if aws.StringValue(input.GroupId) == aws.StringValue(securityGroup.GroupId) {
return &ec2.DeleteSecurityGroupOutput{}, nil
}
}

return nil, awserr.New("NotFound", "Security group not found", nil)
}

func TestEc2_ListSecurityGroups(t *testing.T) {
type fields struct {
session *session.Session
Expand Down Expand Up @@ -906,3 +922,95 @@ func TestEc2_GetSecurityGroup(t *testing.T) {
})
}
}

func TestEc2_DeleteSecurityGroup(t *testing.T) {
type fields struct {
session *session.Session
Service ec2iface.EC2API
DefaultKMSKeyId string
DefaultSgs []string
DefaultSubnets []string
org string
}
type args struct {
ctx context.Context
id string
}
tests := []struct {
name string
fields fields
args args
wantErr bool
}{
{
name: "empty id",
args: args{ctx: context.TODO()},
wantErr: true,
},
{
name: "good id sg-0000000001",
args: args{
ctx: context.TODO(),
id: "sg-0000000001",
},
fields: fields{Service: newmockEC2Client(t, nil)},
},
{
name: "good id sg-0000000002",
args: args{
ctx: context.TODO(),
id: "sg-0000000002",
},
fields: fields{Service: newmockEC2Client(t, nil)},
},
{
name: "good id sg-0000000003",
args: args{
ctx: context.TODO(),
id: "sg-0000000003",
},
fields: fields{Service: newmockEC2Client(t, nil)},
},
{
name: "good id sg-0000000004",
args: args{
ctx: context.TODO(),
id: "sg-0000000004",
},
fields: fields{Service: newmockEC2Client(t, nil)},
},
{
name: "bad id",
args: args{
ctx: context.TODO(),
id: "sg-missing",
},
fields: fields{Service: newmockEC2Client(t, nil)},
wantErr: true,
},
{
name: "aws error",
args: args{
ctx: context.TODO(),
id: "sg-0000000001",
},
fields: fields{Service: newmockEC2Client(t, awserr.New("Bad Request", "boom.", nil))},
wantErr: true,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
e := &Ec2{
session: tt.fields.session,
Service: tt.fields.Service,
DefaultKMSKeyId: tt.fields.DefaultKMSKeyId,
DefaultSgs: tt.fields.DefaultSgs,
DefaultSubnets: tt.fields.DefaultSubnets,
org: tt.fields.org,
}
if err := e.DeleteSecurityGroup(tt.args.ctx, tt.args.id); (err != nil) != tt.wantErr {
t.Errorf("Ec2.DeleteSecurityGroup() error = %v, wantErr %v", err, tt.wantErr)
}
})
}
}
5 changes: 3 additions & 2 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -4,16 +4,17 @@ go 1.15

require (
github.com/YaleSpinup/apierror v0.1.0
github.com/YaleSpinup/aws-go v0.1.0
github.com/aws/amazon-ec2-instance-selector/v2 v2.0.2
github.com/aws/aws-sdk-go v1.37.6
github.com/aws/aws-sdk-go v1.38.50
github.com/google/uuid v1.2.0
github.com/gorilla/handlers v1.5.1
github.com/gorilla/mux v1.8.0
github.com/patrickmn/go-cache v2.1.0+incompatible
github.com/pkg/errors v0.9.1
github.com/prometheus/client_golang v1.9.0
github.com/prometheus/procfs v0.4.1 // indirect
github.com/sirupsen/logrus v1.7.0
github.com/sirupsen/logrus v1.8.1
golang.org/x/crypto v0.0.0-20201221181555-eec23a3978ad
golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c // indirect
google.golang.org/protobuf v1.25.0 // indirect
Expand Down
10 changes: 6 additions & 4 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ github.com/Shopify/toxiproxy v2.1.4+incompatible/go.mod h1:OXgGpZ6Cli1/URJOF1DMx
github.com/VividCortex/gohistogram v1.0.0/go.mod h1:Pf5mBqqDxYaXu3hDrrU+w6nw50o/4+TcAqDqk/vUH7g=
github.com/YaleSpinup/apierror v0.1.0 h1:XiL1AQTsZ9ariWE1BngpDeG+YZjQFX/a/OX25AkWQj8=
github.com/YaleSpinup/apierror v0.1.0/go.mod h1:m68Zb59VAV7MUGwzcYe6vb/FU/DO/QGMbFumkHoyQMQ=
github.com/YaleSpinup/aws-go v0.1.0 h1:Yi2pAfSCoH2AASCROhrliL6givoDOThNVGxQ0RZNHXE=
github.com/YaleSpinup/aws-go v0.1.0/go.mod h1:liyJROxmYM/PCOn6CDT4B5mDcOKhFFCz7hmuymHoRJ4=
github.com/afex/hystrix-go v0.0.0-20180502004556-fa1af6a1f4f5/go.mod h1:SkGFH1ia65gfNATL8TAiHDNxPzPdmEL5uirI2Uyuz6c=
github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
Expand All @@ -26,8 +28,8 @@ github.com/aws/amazon-ec2-instance-selector/v2 v2.0.2/go.mod h1:qot+32DWumAuTogN
github.com/aws/aws-lambda-go v1.13.3/go.mod h1:4UKl9IzQMoD+QF79YdCuzCwp8VbmG4VAQwij/eHl5CU=
github.com/aws/aws-sdk-go v1.27.0/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo=
github.com/aws/aws-sdk-go v1.31.12/go.mod h1:5zCpMtNQVjRREroY7sYe8lOMRSxkhG6MZveU8YkpAk0=
github.com/aws/aws-sdk-go v1.37.6 h1:SWYjRvyZw6DJc3pkZfRWVRD/5wiTDuwOkyb89AAkEBY=
github.com/aws/aws-sdk-go v1.37.6/go.mod h1:hcU610XS61/+aQV88ixoOzUoG7v3b31pl2zKMmprdro=
github.com/aws/aws-sdk-go v1.38.50 h1:9+dEpZbgjBMeoOes6QfZMC87uDMwM8Lw4E79L0/rPZI=
github.com/aws/aws-sdk-go v1.38.50/go.mod h1:hcU610XS61/+aQV88ixoOzUoG7v3b31pl2zKMmprdro=
github.com/aws/aws-sdk-go-v2 v0.18.0/go.mod h1:JWVYvqSMppoMJC0x5wdwiImzgXTI9FuZwxzkQq9wy+g=
github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=
github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8=
Expand Down Expand Up @@ -295,8 +297,8 @@ github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeV
github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=
github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE=
github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88=
github.com/sirupsen/logrus v1.7.0 h1:ShrD1U9pZB12TX0cVy0DtePoCH97K8EtX+mg7ZARUtM=
github.com/sirupsen/logrus v1.7.0/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0=
github.com/sirupsen/logrus v1.8.1 h1:dJKuHgqk1NNQlqoA6BTlM1Wf9DOH3NBjQyu0h9+AZZE=
github.com/sirupsen/logrus v1.8.1/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0=
github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc=
github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA=
github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM=
Expand Down
Loading

0 comments on commit f8698b8

Please sign in to comment.