Skip to content

Commit 50ee33d

Browse files
committed
Enable optional creation of firewall rule for Docker API.
1 parent 76956e4 commit 50ee33d

File tree

4 files changed

+138
-5
lines changed

4 files changed

+138
-5
lines changed

CHANGES.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,11 @@
11
# Changes
22

3+
## v0.9.3
4+
5+
Enhancements:
6+
7+
* The driver now creates a firewall rule to permit Docker API access if `--ddcloud-create-docker-firewall-rule` is specified.
8+
39
## v0.9.2
410

511
Enhancements:

Makefile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
VERSION = 0.9.2
1+
VERSION = 0.9.3
22

33
default: fmt build test
44

client.go

Lines changed: 87 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -586,7 +586,7 @@ func (driver *Driver) createSSHFirewallRule() error {
586586
}
587587

588588
if driver.isSSHFirewallRuleCreated() {
589-
return fmt.Errorf("Firewall rule '%s' has already been created for server '%s'", driver.SSHFirewallRuleID, driver.MachineName)
589+
return fmt.Errorf("SSH firewall rule '%s' has already been created for server '%s'", driver.SSHFirewallRuleID, driver.MachineName)
590590
}
591591

592592
log.Debugf("Creating SSH firewall rule for server '%s' (allow inbound traffic on port %d from '%s' to '%s')...",
@@ -633,7 +633,7 @@ func (driver *Driver) deleteSSHFirewallRule() error {
633633
}
634634

635635
if !driver.isSSHFirewallRuleCreated() {
636-
return fmt.Errorf("Firewall rule has not been created for server '%s'", driver.MachineName)
636+
return fmt.Errorf("SSH firewall rule has not been created for server '%s'", driver.MachineName)
637637
}
638638

639639
log.Debugf("Deleting SSH firewall rule '%s' for server '%s'...",
@@ -651,13 +651,97 @@ func (driver *Driver) deleteSSHFirewallRule() error {
651651
return err
652652
}
653653

654-
log.Debugf("Deleted firewall rule '%s'.", driver.SSHFirewallRuleID)
654+
log.Debugf("Deleted SSH firewall rule '%s'.", driver.SSHFirewallRuleID)
655655

656656
driver.SSHFirewallRuleID = ""
657657

658658
return nil
659659
}
660660

661+
// Has a firewall rule been created to allow inbound Docker for the server?
662+
func (driver *Driver) isDockerFirewallRuleCreated() bool {
663+
return driver.DockerFirewallRuleID != ""
664+
}
665+
666+
// Create a firewall rule to enable inbound Docker connections to the target server from the client machine's (external) IP address.
667+
func (driver *Driver) createDockerFirewallRule() error {
668+
if !driver.isServerCreated() {
669+
return fmt.Errorf("Server '%s' has not been created", driver.MachineName)
670+
}
671+
672+
if driver.isDockerFirewallRuleCreated() {
673+
return fmt.Errorf("Docker firewall rule '%s' has already been created for server '%s'", driver.DockerFirewallRuleID, driver.MachineName)
674+
}
675+
676+
log.Debugf("Creating Docker firewall rule for server '%s' (allow inbound traffic on port %d from '%s' to '%s')...",
677+
driver.MachineName,
678+
DefaultDockerSSLPort,
679+
driver.ClientPublicIPAddress,
680+
driver.IPAddress,
681+
)
682+
683+
ruleConfiguration := compute.FirewallRuleConfiguration{
684+
Name: driver.buildFirewallRuleName("Docker"),
685+
NetworkDomainID: driver.NetworkDomainID,
686+
}
687+
ruleConfiguration.Accept()
688+
ruleConfiguration.Enable()
689+
ruleConfiguration.IPv4()
690+
ruleConfiguration.TCP()
691+
ruleConfiguration.MatchSourceAddress(driver.ClientPublicIPAddress)
692+
ruleConfiguration.MatchDestinationAddress(driver.IPAddress)
693+
ruleConfiguration.MatchDestinationPort(DefaultDockerSSLPort)
694+
ruleConfiguration.PlaceFirst()
695+
696+
client, err := driver.getCloudControlClient()
697+
if err != nil {
698+
return err
699+
}
700+
701+
firewallRuleID, err := client.CreateFirewallRule(ruleConfiguration)
702+
if err != nil {
703+
return err
704+
}
705+
706+
driver.DockerFirewallRuleID = firewallRuleID
707+
708+
log.Debugf("Created Docker firewall rule '%s' for server '%s'.", driver.DockerFirewallRuleID, driver.ServerID)
709+
710+
return nil
711+
}
712+
713+
// Delete the firewall rule that enables inbound Docker connections to the target server from the client machine's (external) IP address.
714+
func (driver *Driver) deleteDockerFirewallRule() error {
715+
if !driver.isServerCreated() {
716+
return fmt.Errorf("Server '%s' has not been created", driver.MachineName)
717+
}
718+
719+
if !driver.isDockerFirewallRuleCreated() {
720+
return fmt.Errorf("Docker firewall rule has not been created for server '%s'", driver.MachineName)
721+
}
722+
723+
log.Debugf("Deleting Docker firewall rule '%s' for server '%s'...",
724+
driver.MachineName,
725+
driver.DockerFirewallRuleID,
726+
)
727+
728+
client, err := driver.getCloudControlClient()
729+
if err != nil {
730+
return err
731+
}
732+
733+
err = client.DeleteFirewallRule(driver.DockerFirewallRuleID)
734+
if err != nil {
735+
return err
736+
}
737+
738+
log.Debugf("Deleted Docker firewall rule '%s'.", driver.DockerFirewallRuleID)
739+
740+
driver.DockerFirewallRuleID = ""
741+
742+
return nil
743+
}
744+
661745
// Name sanitiser for firewall rules.
662746
var firewallRuleNameSanitizer = strings.NewReplacer("-", ".", "_", ".")
663747

driver.go

Lines changed: 44 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,9 @@ import (
2121
// DefaultImageName is the name of the default OS image used to create machines.
2222
const DefaultImageName = "Ubuntu 14.04 2 CPU"
2323

24+
// DefaultDockerSSLPort is the default SSL API port used by Docker.
25+
const DefaultDockerSSLPort = 2376
26+
2427
// Driver is the Docker Machine driver for Dimension Data CloudControl.
2528
type Driver struct {
2629
*drivers.BaseDriver
@@ -81,12 +84,18 @@ type Driver struct {
8184
// The initial password used to authenticate to target machines when installing the SSH key.
8285
SSHBootstrapPassword string
8386

84-
// Create a firewall rule to allow SSH access to the taret server?
87+
// Create a firewall rule to allow SSH access to the target server?
8588
CreateSSHFirewallRule bool
8689

90+
// Create a firewall rule to allow Docker API access to the target server?
91+
CreateDockerFirewallRule bool
92+
8793
// The Id of the firewall rule (if any) created for inbound SSH access to the target server.
8894
SSHFirewallRuleID string
8995

96+
// The Id of the firewall rule (if any) created for inbound Docker API access to the target server.
97+
DockerFirewallRuleID string
98+
9099
// The client's public (external) IP address.
91100
ClientPublicIPAddress string
92101

@@ -175,6 +184,10 @@ func (driver *Driver) GetCreateFlags() []mcnflag.Flag {
175184
Name: "ddcloud-create-ssh-firewall-rule",
176185
Usage: "Create a firewall rule to allow SSH access to the target server? Default: false",
177186
},
187+
mcnflag.BoolFlag{
188+
Name: "ddcloud-create-docker-firewall-rule",
189+
Usage: "Create a firewall rule to allow Docker API access to the target server? Default: false",
190+
},
178191
mcnflag.StringFlag{
179192
EnvVar: "MCP_CLIENT_PUBLIC_IP",
180193
Name: "ddcloud-client-public-ip",
@@ -214,6 +227,7 @@ func (driver *Driver) SetConfigFromFlags(flags drivers.DriverOptions) error {
214227
driver.SSHBootstrapPassword = flags.String("ddcloud-ssh-bootstrap-password")
215228

216229
driver.CreateSSHFirewallRule = flags.Bool("ddcloud-create-ssh-firewall-rule")
230+
driver.CreateDockerFirewallRule = flags.Bool("ddcloud-create-ssh-firewall-rule")
217231
driver.ClientPublicIPAddress = flags.String("ddcloud-client-public-ip")
218232
driver.UsePrivateIP = flags.Bool("ddcloud-use-private-ip")
219233

@@ -322,6 +336,28 @@ func (driver *Driver) Create() error {
322336
return err
323337
}
324338
}
339+
340+
if driver.CreateDockerFirewallRule {
341+
if driver.ClientPublicIPAddress == "" {
342+
driver.ClientPublicIPAddress, err = getClientPublicIPv4Address()
343+
if err != nil {
344+
return err
345+
}
346+
}
347+
348+
log.Infof("Creating firewall rule to enable inbound Docker API traffic from local machine '%s' ('%s') to '%s' ('%s':%d)...",
349+
os.Getenv("HOST"),
350+
driver.ClientPublicIPAddress,
351+
driver.MachineName,
352+
driver.IPAddress,
353+
DefaultDockerSSLPort,
354+
)
355+
356+
err = driver.createDockerFirewallRule()
357+
if err != nil {
358+
return err
359+
}
360+
}
325361
} else {
326362
log.Infof("Server '%s' has private IP '%s'.", driver.MachineName, driver.PrivateIPAddress)
327363
}
@@ -402,6 +438,13 @@ func (driver *Driver) Remove() error {
402438
}
403439
}
404440

441+
if driver.isDockerFirewallRuleCreated() {
442+
err = driver.deleteDockerFirewallRule()
443+
if err != nil {
444+
return err
445+
}
446+
}
447+
405448
if driver.isNATRuleCreated() {
406449
err = driver.deleteNATRuleForServer()
407450
if err != nil {

0 commit comments

Comments
 (0)