Skip to content

Commit 142f46c

Browse files
committed
libn/d/overlay: enforce encryption on sandbox init
The iptables rules which make encryption mandatory on an encrypted overlay network are only programmed once there is a second node participating in the network. This leaves single-node encrypted overlay networks vulnerable to packet injection. Furthermore, failure to program the rules is not treated as a fatal error. Program the iptables rules to make encryption mandatory before creating the VXLAN link to guarantee that there is no window of time where incoming cleartext VXLAN packets for the network would be accepted, or outgoing cleartext packets be transmitted. Only create the VXLAN link if programming the rules succeeds to ensure that it fails closed. Signed-off-by: Cory Snider <[email protected]>
1 parent d4fd582 commit 142f46c

4 files changed

Lines changed: 33 additions & 32 deletions

File tree

libnetwork/drivers/overlay/encryption.go

Lines changed: 17 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -112,8 +112,8 @@ func (e *encrMap) String() string {
112112
return b.String()
113113
}
114114

115-
func (d *driver) checkEncryption(nid string, rIP net.IP, vxlanID uint32, isLocal, add bool) error {
116-
logrus.Debugf("checkEncryption(%.7s, %v, %d, %t)", nid, rIP, vxlanID, isLocal)
115+
func (d *driver) checkEncryption(nid string, rIP net.IP, isLocal, add bool) error {
116+
logrus.Debugf("checkEncryption(%.7s, %v, %t)", nid, rIP, isLocal)
117117

118118
n := d.network(nid)
119119
if n == nil || !n.secure {
@@ -148,7 +148,7 @@ func (d *driver) checkEncryption(nid string, rIP net.IP, vxlanID uint32, isLocal
148148

149149
if add {
150150
for _, rIP := range nodes {
151-
if err := setupEncryption(lIP, aIP, rIP, vxlanID, d.secMap, d.keys); err != nil {
151+
if err := setupEncryption(lIP, aIP, rIP, d.secMap, d.keys); err != nil {
152152
logrus.Warnf("Failed to program network encryption between %s and %s: %v", lIP, rIP, err)
153153
}
154154
}
@@ -163,22 +163,14 @@ func (d *driver) checkEncryption(nid string, rIP net.IP, vxlanID uint32, isLocal
163163
return nil
164164
}
165165

166-
func setupEncryption(localIP, advIP, remoteIP net.IP, vni uint32, em *encrMap, keys []*key) error {
167-
logrus.Debugf("Programming encryption for vxlan %d between %s and %s", vni, localIP, remoteIP)
166+
// setupEncryption programs the encryption parameters for secure communication
167+
// between the local node and a remote node.
168+
func setupEncryption(localIP, advIP, remoteIP net.IP, em *encrMap, keys []*key) error {
169+
logrus.Debugf("Programming encryption between %s and %s", localIP, remoteIP)
168170
rIPs := remoteIP.String()
169171

170172
indices := make([]*spi, 0, len(keys))
171173

172-
err := programMangle(vni, true)
173-
if err != nil {
174-
logrus.Warn(err)
175-
}
176-
177-
err = programInput(vni, true)
178-
if err != nil {
179-
logrus.Warn(err)
180-
}
181-
182174
for i, k := range keys {
183175
spis := &spi{buildSPI(advIP, remoteIP, k.tag), buildSPI(remoteIP, advIP, k.tag)}
184176
dir := reverse
@@ -233,37 +225,33 @@ func removeEncryption(localIP, remoteIP net.IP, em *encrMap) error {
233225
return nil
234226
}
235227

236-
func programMangle(vni uint32, add bool) (err error) {
228+
func programMangle(vni uint32, add bool) error {
237229
var (
238230
p = strconv.FormatUint(uint64(overlayutils.VXLANUDPPort()), 10)
239231
c = fmt.Sprintf("0>>22&0x3C@12&0xFFFFFF00=%d", int(vni)<<8)
240232
m = strconv.FormatUint(mark, 10)
241233
chain = "OUTPUT"
242234
rule = []string{"-p", "udp", "--dport", p, "-m", "u32", "--u32", c, "-j", "MARK", "--set-mark", m}
243-
a = "-A"
235+
a = iptables.Append
244236
action = "install"
245237
)
246238

247239
// TODO IPv6 support
248240
iptable := iptables.GetIptable(iptables.IPv4)
249241

250-
if add == iptable.Exists(iptables.Mangle, chain, rule...) {
251-
return
252-
}
253-
254242
if !add {
255-
a = "-D"
243+
a = iptables.Delete
256244
action = "remove"
257245
}
258246

259-
if err = iptable.RawCombinedOutput(append([]string{"-t", string(iptables.Mangle), a, chain}, rule...)...); err != nil {
260-
logrus.Warnf("could not %s mangle rule: %v", action, err)
247+
if err := iptable.ProgramRule(iptables.Mangle, chain, a, rule); err != nil {
248+
return fmt.Errorf("could not %s mangle rule: %w", action, err)
261249
}
262250

263-
return
251+
return nil
264252
}
265253

266-
func programInput(vni uint32, add bool) (err error) {
254+
func programInput(vni uint32, add bool) error {
267255
var (
268256
port = strconv.FormatUint(uint64(overlayutils.VXLANUDPPort()), 10)
269257
vniMatch = fmt.Sprintf("0>>22&0x3C@12&0xFFFFFF00=%d", int(vni)<<8)
@@ -286,15 +274,15 @@ func programInput(vni uint32, add bool) (err error) {
286274

287275
// Accept incoming VXLAN datagrams for the VNI which were subjected to IPSec processing.
288276
if err := iptable.ProgramRule(iptables.Filter, chain, action, accept); err != nil {
289-
logrus.Errorf("could not %s input rule: %v. Please do it manually.", msg, err)
277+
return fmt.Errorf("could not %s input accept rule: %w", msg, err)
290278
}
291279

292280
// Drop incoming VXLAN datagrams for the VNI which were received in cleartext.
293281
if err := iptable.ProgramRule(iptables.Filter, chain, action, block); err != nil {
294-
logrus.Errorf("could not %s input rule: %v. Please do it manually.", msg, err)
282+
return fmt.Errorf("could not %s input drop rule: %w", msg, err)
295283
}
296284

297-
return
285+
return nil
298286
}
299287

300288
func programSA(localIP, remoteIP net.IP, spi *spi, k *key, dir int, add bool) (fSA *netlink.XfrmState, rSA *netlink.XfrmState, err error) {

libnetwork/drivers/overlay/joinleave.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -117,7 +117,7 @@ func (d *driver) Join(nid, eid string, sboxKey string, jinfo driverapi.JoinInfo,
117117

118118
d.peerAdd(nid, eid, ep.addr.IP, ep.addr.Mask, ep.mac, net.ParseIP(d.advertiseAddress), false, false, true)
119119

120-
if err = d.checkEncryption(nid, nil, n.vxlanID(s), true, true); err != nil {
120+
if err = d.checkEncryption(nid, nil, true, true); err != nil {
121121
logrus.Warn(err)
122122
}
123123

libnetwork/drivers/overlay/ov_network.go

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ import (
2222
"github.com/docker/docker/libnetwork/osl"
2323
"github.com/docker/docker/libnetwork/resolvconf"
2424
"github.com/docker/docker/libnetwork/types"
25+
"github.com/hashicorp/go-multierror"
2526
"github.com/sirupsen/logrus"
2627
"github.com/vishvananda/netlink"
2728
"github.com/vishvananda/netlink/nl"
@@ -654,6 +655,18 @@ func (n *network) initSubnetSandbox(s *subnet, restore bool) error {
654655
brName := n.generateBridgeName(s)
655656
vxlanName := n.generateVxlanName(s)
656657

658+
// Program iptables rules for mandatory encryption of the secure
659+
// network, or clean up leftover rules for a stale secure network which
660+
// was previously assigned the same VNI.
661+
if err := programMangle(s.vni, n.secure); err != nil {
662+
return err
663+
}
664+
if err := programInput(s.vni, n.secure); err != nil {
665+
if n.secure {
666+
return multierror.Append(err, programMangle(s.vni, false))
667+
}
668+
}
669+
657670
if restore {
658671
if err := n.restoreSubnetSandbox(s, brName, vxlanName); err != nil {
659672
return err

libnetwork/drivers/overlay/peerdb.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -387,7 +387,7 @@ func (d *driver) peerAddOp(nid, eid string, peerIP net.IP, peerIPMask net.IPMask
387387
return fmt.Errorf("subnet sandbox join failed for %q: %v", s.subnetIP.String(), err)
388388
}
389389

390-
if err := d.checkEncryption(nid, vtep, n.vxlanID(s), false, true); err != nil {
390+
if err := d.checkEncryption(nid, vtep, false, true); err != nil {
391391
logrus.Warn(err)
392392
}
393393

@@ -447,7 +447,7 @@ func (d *driver) peerDeleteOp(nid, eid string, peerIP net.IP, peerIPMask net.IPM
447447
return nil
448448
}
449449

450-
if err := d.checkEncryption(nid, vtep, 0, localPeer, false); err != nil {
450+
if err := d.checkEncryption(nid, vtep, localPeer, false); err != nil {
451451
logrus.Warn(err)
452452
}
453453

0 commit comments

Comments
 (0)