Merge lp:~gz/juju-core/trunk-security-group-group-id-1226996 into lp:~go-bot/juju-core/trunk

Proposed by Martin Packman
Status: Merged
Approved by: Martin Packman
Approved revision: no longer in the source branch.
Merged at revision: 1857
Proposed branch: lp:~gz/juju-core/trunk-security-group-group-id-1226996
Merge into: lp:~go-bot/juju-core/trunk
Diff against target: 238 lines (+142/-9)
4 files modified
environs/jujutest/livetests.go (+4/-0)
provider/openstack/export_test.go (+24/-0)
provider/openstack/live_test.go (+84/-0)
provider/openstack/provider.go (+30/-9)
To merge this branch: bzr merge lp:~gz/juju-core/trunk-security-group-group-id-1226996
Reviewer Review Type Date Requested Status
Juju Engineering Pending
Review via email: mp+186586@code.launchpad.net

Commit message

provider/openstack: bug #1226996 SecurityGroup

We intended to allow access to any port for any instance in the
default security group. However, we didn't specify a CIDR and we
didn't reference the Source Group Id. Which meant we actually were
exposing *all* ports to *all* machines.

This is a cherrypick from 1.14 rather than a merge up of all
changes, as the two branches are surprisingly diverged.

https://codereview.appspot.com/13787043/

R=rogpeppe

Description of the change

provider/openstack: bug #1226996 SecurityGroup

We intended to allow access to any port for any instance in the
default security group. However, we didn't specify a CIDR and we
didn't reference the Source Group Id. Which meant we actually were
exposing *all* ports to *all* machines.

This is a cherrypick from 1.14 rather than a merge up of all
changes, as the two branches are surprisingly diverged.

https://codereview.appspot.com/13787043/

To post a comment you must log in.
Revision history for this message
Martin Packman (gz) wrote :

Reviewers: mp+186586_code.launchpad.net,

Message:
Please take a look.

Description:
provider/openstack: bug #1226996 SecurityGroup

We intended to allow access to any port for any instance in the
default security group. However, we didn't specify a CIDR and we
didn't reference the Source Group Id. Which meant we actually were
exposing *all* ports to *all* machines.

This is a cherrypick from 1.14 rather than a merge up of all
changes, as the two branches are surprisingly diverged.

https://code.launchpad.net/~gz/juju-core/trunk-security-group-group-id-1226996/+merge/186586

(do not edit description out of merge proposal)

Please review this at https://codereview.appspot.com/13787043/

Affected files (+144, -9 lines):
   A [revision details]
   M environs/jujutest/livetests.go
   M provider/openstack/export_test.go
   M provider/openstack/live_test.go
   M provider/openstack/provider.go

Revision history for this message
Roger Peppe (rogpeppe) wrote :

On 2013/09/19 16:59:34, gz wrote:
> Please take a look.

LGTM assuming you've tested it live and the expose logic works
as expected.

https://codereview.appspot.com/13787043/

Revision history for this message
John A Meinel (jameinel) wrote :

-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

>
> This is a cherrypick from 1.14 rather than a merge up of all
> changes, as the two branches are surprisingly diverged.
>

I would really like to see us get convergence here, but doing this
short term is ok. (It is only going to get harder in the future, and
make it more difficult to make bugfixes on stable branches.)

John
=:->

-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.13 (Cygwin)
Comment: Using GnuPG with Thunderbird - http://www.enigmail.net/

iEYEARECAAYFAlI8RIoACgkQJdeBCYSNAAPveQCcDTaoVOKLQywXybv+ftDKOGsW
o/UAnAzo8/ulGMxAe0oJXdHLH7oKU++n
=A+Sx
-----END PGP SIGNATURE-----

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'environs/jujutest/livetests.go'
2--- environs/jujutest/livetests.go 2013-09-18 22:54:32 +0000
3+++ environs/jujutest/livetests.go 2013-09-19 17:18:25 +0000
4@@ -514,6 +514,10 @@
5 conn, err := juju.NewConn(t.Env)
6 c.Assert(err, gc.IsNil)
7 conn.Close()
8+
9+ apiConn, err := juju.NewAPIConn(t.Env, api.DefaultDialOpts())
10+ c.Assert(err, gc.IsNil)
11+ apiConn.Close()
12 }
13
14 func (t *LiveTests) TestCheckEnvironmentOnConnectNoVerificationFile(c *gc.C) {
15
16=== modified file 'provider/openstack/export_test.go'
17--- provider/openstack/export_test.go 2013-09-18 07:13:09 +0000
18+++ provider/openstack/export_test.go 2013-09-19 17:18:25 +0000
19@@ -9,6 +9,7 @@
20 "strings"
21 "text/template"
22
23+ "launchpad.net/goose/errors"
24 "launchpad.net/goose/identity"
25 "launchpad.net/goose/nova"
26 "launchpad.net/goose/swift"
27@@ -236,6 +237,25 @@
28 WritablePublicStorage(e).Remove(productMetadatafile)
29 }
30
31+// DiscardSecurityGroup cleans up a security group, it is not an error to
32+// delete something that doesn't exist.
33+func DiscardSecurityGroup(e environs.Environ, name string) error {
34+ env := e.(*environ)
35+ novaClient := env.nova()
36+ group, err := novaClient.SecurityGroupByName(name)
37+ if err != nil {
38+ if errors.IsNotFound(err) {
39+ // Group already deleted, done
40+ return nil
41+ }
42+ }
43+ err = novaClient.DeleteSecurityGroup(group.Id)
44+ if err != nil {
45+ return err
46+ }
47+ return nil
48+}
49+
50 func FindInstanceSpec(e environs.Environ, series, arch, cons string) (spec *instances.InstanceSpec, err error) {
51 env := e.(*environ)
52 spec, err = findInstanceSpec(env, &instances.InstanceConstraint{
53@@ -261,6 +281,10 @@
54 env.ecfg().attrs["use-floating-ip"] = val
55 }
56
57+func SetUpGlobalGroup(e environs.Environ, name string, statePort, apiPort int) (nova.SecurityGroup, error) {
58+ return e.(*environ).setUpGlobalGroup(name, statePort, apiPort)
59+}
60+
61 func EnsureGroup(e environs.Environ, name string, rules []nova.RuleInfo) (nova.SecurityGroup, error) {
62 return e.(*environ).ensureGroup(name, rules)
63 }
64
65=== modified file 'provider/openstack/live_test.go'
66--- provider/openstack/live_test.go 2013-09-18 07:13:09 +0000
67+++ provider/openstack/live_test.go 2013-09-19 17:18:25 +0000
68@@ -7,11 +7,13 @@
69 "crypto/rand"
70 "fmt"
71 "io"
72+ "sort"
73
74 gc "launchpad.net/gocheck"
75
76 "launchpad.net/goose/client"
77 "launchpad.net/goose/identity"
78+ "launchpad.net/goose/nova"
79
80 "launchpad.net/juju-core/environs/jujutest"
81 "launchpad.net/juju-core/environs/storage"
82@@ -126,3 +128,85 @@
83 t.LiveTests.TearDownTest(c)
84 t.LoggingSuite.TearDownTest(c)
85 }
86+
87+func (t *LiveTests) TestEnsureGroupSetsGroupId(c *gc.C) {
88+ rules := []nova.RuleInfo{
89+ { // First group explicitly asks for all services
90+ IPProtocol: "tcp",
91+ FromPort: 22,
92+ ToPort: 22,
93+ Cidr: "0.0.0.0/0",
94+ },
95+ { // Second group should only allow access from within the group
96+ IPProtocol: "tcp",
97+ FromPort: 1,
98+ ToPort: 65535,
99+ },
100+ }
101+ groupName := "juju-test-group-" + randomName()
102+ // Make sure things are clean before we start, and clean when we are done
103+ cleanup := func() {
104+ c.Check(openstack.DiscardSecurityGroup(t.Env, groupName), gc.IsNil)
105+ }
106+ cleanup()
107+ defer cleanup()
108+ group, err := openstack.EnsureGroup(t.Env, groupName, rules)
109+ c.Assert(err, gc.IsNil)
110+ c.Check(group.Rules, gc.HasLen, 2)
111+ c.Check(*group.Rules[0].IPProtocol, gc.Equals, "tcp")
112+ c.Check(*group.Rules[0].FromPort, gc.Equals, 22)
113+ c.Check(*group.Rules[0].ToPort, gc.Equals, 22)
114+ c.Check(group.Rules[0].IPRange["cidr"], gc.Equals, "0.0.0.0/0")
115+ c.Check(group.Rules[0].Group.Name, gc.Equals, "")
116+ c.Check(group.Rules[0].Group.TenantId, gc.Equals, "")
117+ c.Check(*group.Rules[1].IPProtocol, gc.Equals, "tcp")
118+ c.Check(*group.Rules[1].FromPort, gc.Equals, 1)
119+ c.Check(*group.Rules[1].ToPort, gc.Equals, 65535)
120+ c.Check(group.Rules[1].IPRange, gc.HasLen, 0)
121+ c.Check(group.Rules[1].Group.Name, gc.Equals, groupName)
122+ c.Check(group.Rules[1].Group.TenantId, gc.Equals, group.TenantId)
123+}
124+
125+func (t *LiveTests) TestSetupGlobalGroupExposesCorrectPorts(c *gc.C) {
126+ groupName := "juju-test-group-" + randomName()
127+ // Make sure things are clean before we start, and will be clean when we finish
128+ cleanup := func() {
129+ c.Check(openstack.DiscardSecurityGroup(t.Env, groupName), gc.IsNil)
130+ }
131+ cleanup()
132+ defer cleanup()
133+ statePort := 12345 // Default 37017
134+ apiPort := 34567 // Default 17070
135+ group, err := openstack.SetUpGlobalGroup(t.Env, groupName, statePort, apiPort)
136+ c.Assert(err, gc.IsNil)
137+ c.Assert(err, gc.IsNil)
138+ // We default to exporting 22, statePort, apiPort, and icmp/udp/tcp on
139+ // all ports to other machines inside the same group
140+ // TODO(jam): 2013-09-18 http://pad.lv/1227142
141+ // We shouldn't be exposing the API and State ports on all the machines
142+ // that *aren't* hosting the state server. (And once we finish
143+ // client-via-API we can disable the State port as well.)
144+ stringRules := make([]string, 0, len(group.Rules))
145+ for _, rule := range group.Rules {
146+ ruleStr := fmt.Sprintf("%s %d %d %q %q",
147+ *rule.IPProtocol,
148+ *rule.FromPort,
149+ *rule.ToPort,
150+ rule.IPRange["cidr"],
151+ rule.Group.Name,
152+ )
153+ stringRules = append(stringRules, ruleStr)
154+ }
155+ // We don't care about the ordering, so we sort the result, and compare it.
156+ expectedRules := []string{
157+ `tcp 22 22 "0.0.0.0/0" ""`,
158+ fmt.Sprintf(`tcp %d %d "0.0.0.0/0" ""`, statePort, statePort),
159+ fmt.Sprintf(`tcp %d %d "0.0.0.0/0" ""`, apiPort, apiPort),
160+ fmt.Sprintf(`tcp 1 65535 "" "%s"`, groupName),
161+ fmt.Sprintf(`udp 1 65535 "" "%s"`, groupName),
162+ fmt.Sprintf(`icmp -1 -1 "" "%s"`, groupName),
163+ }
164+ sort.Strings(stringRules)
165+ sort.Strings(expectedRules)
166+ c.Check(stringRules, gc.DeepEquals, expectedRules)
167+}
168
169=== modified file 'provider/openstack/provider.go'
170--- provider/openstack/provider.go 2013-09-18 07:13:09 +0000
171+++ provider/openstack/provider.go 2013-09-19 17:18:25 +0000
172@@ -991,15 +991,8 @@
173 return &providerInstance
174 }
175
176-// setUpGroups creates the security groups for the new machine, and
177-// returns them.
178-//
179-// Instances are tagged with a group so they can be distinguished from
180-// other instances that might be running on the same OpenStack account.
181-// In addition, a specific machine security group is created for each
182-// machine, so that its firewall rules can be configured per machine.
183-func (e *environ) setUpGroups(machineId string, statePort, apiPort int) ([]nova.SecurityGroup, error) {
184- jujuGroup, err := e.ensureGroup(e.jujuGroupName(),
185+func (e *environ) setUpGlobalGroup(groupName string, statePort, apiPort int) (nova.SecurityGroup, error) {
186+ return e.ensureGroup(groupName,
187 []nova.RuleInfo{
188 {
189 IPProtocol: "tcp",
190@@ -1015,6 +1008,12 @@
191 },
192 {
193 IPProtocol: "tcp",
194+ FromPort: apiPort,
195+ ToPort: apiPort,
196+ Cidr: "0.0.0.0/0",
197+ },
198+ {
199+ IPProtocol: "tcp",
200 FromPort: 1,
201 ToPort: 65535,
202 },
203@@ -1029,6 +1028,21 @@
204 ToPort: -1,
205 },
206 })
207+}
208+
209+// setUpGroups creates the security groups for the new machine, and
210+// returns them.
211+//
212+// Instances are tagged with a group so they can be distinguished from
213+// other instances that might be running on the same OpenStack account.
214+// In addition, a specific machine security group is created for each
215+// machine, so that its firewall rules can be configured per machine.
216+//
217+// Note: ideally we'd have a better way to determine group membership so that 2
218+// people that happen to share an openstack account and name their environment
219+// "openstack" don't end up destroying each other's machines.
220+func (e *environ) setUpGroups(machineId string, statePort, apiPort int) ([]nova.SecurityGroup, error) {
221+ jujuGroup, err := e.setUpGlobalGroup(e.jujuGroupName(), statePort, apiPort)
222 if err != nil {
223 return nil, err
224 }
225@@ -1077,6 +1091,13 @@
226 group.Rules = make([]nova.SecurityGroupRule, len(rules))
227 for i, rule := range rules {
228 rule.ParentGroupId = group.Id
229+ if rule.Cidr == "" {
230+ // http://pad.lv/1226996 Rules that don't have a CIDR
231+ // are meant to apply only to this group. If you don't
232+ // supply CIDR or GroupId then openstack assumes you
233+ // mean CIDR=0.0.0.0/0
234+ rule.GroupId = &group.Id
235+ }
236 groupRule, err := novaClient.CreateSecurityGroupRule(rule)
237 if err != nil && !gooseerrors.IsDuplicateValue(err) {
238 return zeroGroup, err

Subscribers

People subscribed via source and target branches

to status/vote changes: