Skip to content

Commit c356c43

Browse files
committed
Initial support for creating firewall rule for inbound SSH.
1 parent a445448 commit c356c43

File tree

4 files changed

+112
-14
lines changed

4 files changed

+112
-14
lines changed

Makefile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,4 +32,4 @@ test: fmt
3232
go test -v github.com/DimensionDataResearch/docker-machine-driver-ddcloud/...
3333

3434
version:
35-
echo "package main\n\n// DriverVersion is the current version of the CloudControl driver for Docker Machine.\nconst DriverVersion = \"v0.1 (`git rev-parse HEAD`)\"" > ./version-info.go
35+
echo "package main\n\n// DriverVersion is the current version of the CloudControl driver for Docker Machine.\nconst DriverVersion = \"v0.2 (`git rev-parse HEAD`)\"" > ./version-info.go

client.go

Lines changed: 81 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,12 @@ import (
55
"fmt"
66
"github.com/DimensionDataResearch/go-dd-cloud-compute/compute"
77
"github.com/docker/machine/libmachine/log"
8+
"strings"
89
"time"
910
)
1011

12+
var firewallRuleNameSanitizer = strings.NewReplacer("-", ".", "_", ".")
13+
1114
// Get the CloudControl API client used by the driver.
1215
func (driver *Driver) getCloudControlClient() (client *compute.Client, err error) {
1316
client = driver.client
@@ -49,7 +52,7 @@ func (driver *Driver) isServerCreated() bool {
4952
// Retrieve the target server (must have been created, or an error is returned).
5053
func (driver *Driver) getServer() (*compute.Server, error) {
5154
if !driver.isServerCreated() {
52-
return nil, errors.New("Server has not been created")
55+
return nil, fmt.Errorf("Server '%s' has not been created", driver.MachineName)
5356
}
5457

5558
client, err := driver.getCloudControlClient()
@@ -273,7 +276,7 @@ func (driver *Driver) isNATRuleCreated() bool {
273276
// Create a NAT rule to expose the server.
274277
func (driver *Driver) createNATRuleForServer() error {
275278
if !driver.isServerCreated() {
276-
return errors.New("Server has not been created")
279+
return fmt.Errorf("Server '%s' has not been created", driver.MachineName)
277280
}
278281

279282
if driver.isNATRuleCreated() {
@@ -328,7 +331,7 @@ func (driver *Driver) createNATRuleForServer() error {
328331
// Delete the the server's NAT rule (if any).
329332
func (driver *Driver) deleteNATRuleForServer() error {
330333
if !driver.isServerCreated() {
331-
return errors.New("Server has not been created")
334+
return fmt.Errorf("Server '%s' has not been created", driver.MachineName)
332335
}
333336

334337
if !driver.isNATRuleCreated() {
@@ -439,3 +442,78 @@ func (driver *Driver) ensurePublicIPAvailable() error {
439442
func (driver *Driver) isSSHFirewallRuleCreated() bool {
440443
return driver.SSHFirewallRuleID != ""
441444
}
445+
446+
// Create a firewall rule to enable inbound SSH connections to the target server from the client machine's (external) IP address.
447+
func (driver *Driver) createSSHFirewallRule(clientPublicIPAddress string) error {
448+
if !driver.isServerCreated() {
449+
return fmt.Errorf("Server '%s' has not been created", driver.MachineName)
450+
}
451+
452+
if driver.isSSHFirewallRuleCreated() {
453+
return fmt.Errorf("Firewall rule '%s' has already been created for server '%s'", driver.SSHFirewallRuleID, driver.MachineName)
454+
}
455+
456+
log.Debugf("Creating SSH firewall rule for server '%s' (allow inbound traffic on port %d from '%s' to '%s')...",
457+
driver.MachineName,
458+
driver.SSHPort,
459+
clientPublicIPAddress,
460+
driver.IPAddress,
461+
)
462+
463+
ruleConfiguration := compute.FirewallRuleConfiguration{
464+
Name: firewallRuleNameSanitizer.Replace(driver.MachineName),
465+
}
466+
ruleConfiguration.Accept()
467+
ruleConfiguration.Enable()
468+
ruleConfiguration.MatchSourceAddress(clientPublicIPAddress)
469+
ruleConfiguration.MatchDestinationAddress(driver.IPAddress)
470+
ruleConfiguration.MatchDestinationPort(driver.SSHPort)
471+
472+
client, err := driver.getCloudControlClient()
473+
if err != nil {
474+
return err
475+
}
476+
477+
firewallRuleID, err := client.CreateFirewallRule(ruleConfiguration)
478+
if err != nil {
479+
return err
480+
}
481+
482+
driver.SSHFirewallRuleID = firewallRuleID
483+
484+
log.Debugf("Created SSH firewall rule '%s' for server '%s'.", driver.SSHFirewallRuleID, driver.ServerID)
485+
486+
return nil
487+
}
488+
489+
// Delete the firewall rule that enables inbound SSH connections to the target server from the client machine's (external) IP address.
490+
func (driver *Driver) deleteSSHFirewallRule() error {
491+
if !driver.isServerCreated() {
492+
return fmt.Errorf("Server '%s' has not been created", driver.MachineName)
493+
}
494+
495+
if !driver.isSSHFirewallRuleCreated() {
496+
return fmt.Errorf("Firewall rule has not been created for server '%s'", driver.MachineName)
497+
}
498+
499+
log.Debugf("Deleting SSH firewall rule '%s' for server '%s'...",
500+
driver.MachineName,
501+
driver.SSHFirewallRuleID,
502+
)
503+
504+
client, err := driver.getCloudControlClient()
505+
if err != nil {
506+
return err
507+
}
508+
509+
err = client.DeleteFirewallRule(driver.SSHFirewallRuleID)
510+
if err != nil {
511+
return err
512+
}
513+
514+
log.Debugf("Deleted firewall rule '%s'.", driver.SSHFirewallRuleID)
515+
516+
driver.SSHFirewallRuleID = ""
517+
518+
return nil
519+
}

get_my_public_ip.go renamed to client_public_ip.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,8 @@ type ipInfo struct {
1111
IPAddress string `json:"ip"`
1212
}
1313

14-
// Retrieve the local machine's public IPv4 address.
15-
func getMyPublicIPv4Address() (string, error) {
14+
// Retrieve the client machine's public IPv4 address.
15+
func getClientPublicIPv4Address() (string, error) {
1616
response, err := http.Get("http://ifconfig.co/json")
1717
if err != nil {
1818
return "", err

driver.go

Lines changed: 28 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -212,15 +212,9 @@ func (driver *Driver) PreCreateCheck() error {
212212

213213
// Create a new Docker Machine instance on CloudControl.
214214
func (driver *Driver) Create() error {
215-
localPublicIP, err := getMyPublicIPv4Address()
216-
if err != nil {
217-
return err
218-
}
219-
log.Infof("Local machine's public IP address is '%s'.", localPublicIP)
220-
221215
log.Infof("Importing SSH key...")
222216

223-
err = driver.importSSHKey()
217+
err := driver.importSSHKey()
224218
if err != nil {
225219
return err
226220
}
@@ -239,6 +233,20 @@ func (driver *Driver) Create() error {
239233
log.Infof("Server '%s' has private IP '%s'.", driver.MachineName, driver.PrivateIPAddress)
240234
log.Infof("Server '%s' has public IP '%s'.", driver.MachineName, driver.IPAddress)
241235

236+
if driver.CreateSSHFirewallRule {
237+
var clientPublicIPAddress string
238+
clientPublicIPAddress, err = getClientPublicIPv4Address()
239+
if err != nil {
240+
return err
241+
}
242+
log.Infof("Local machine's public IP address is '%s'.", clientPublicIPAddress)
243+
244+
err = driver.createSSHFirewallRule(clientPublicIPAddress)
245+
if err != nil {
246+
return err
247+
}
248+
}
249+
242250
log.Infof("Configuring SSH key for server '%s' ('%s')...", driver.MachineName, driver.IPAddress)
243251
err = driver.installSSHKey()
244252
if err != nil {
@@ -308,7 +316,19 @@ func (driver *Driver) Remove() error {
308316
return err
309317
}
310318

311-
// TODO: Delete server's associated NAT rule, if required.
319+
if driver.isSSHFirewallRuleCreated() {
320+
err = driver.deleteSSHFirewallRule()
321+
if err != nil {
322+
return err
323+
}
324+
}
325+
326+
if driver.isNATRuleCreated() {
327+
err = driver.deleteNATRuleForServer()
328+
if err != nil {
329+
return err
330+
}
331+
}
312332

313333
err = client.DeleteServer(driver.ServerID)
314334
if err != nil {

0 commit comments

Comments
 (0)