Skip to content

Commit

Permalink
azure: network security groups: implement
Browse files Browse the repository at this point in the history
  • Loading branch information
Phreedom committed Mar 23, 2016
1 parent 9dd7f63 commit b5d0b1d
Show file tree
Hide file tree
Showing 6 changed files with 399 additions and 1 deletion.
155 changes: 155 additions & 0 deletions nix/azure-network-security-group.nix
@@ -0,0 +1,155 @@
{ config, lib, pkgs, uuid, name, resources, ... }:

with lib;
with (import ./lib.nix lib);
let

securityRuleOptions = { config, ... }: {
options = {
description = mkOption {
default = "";
example = "Allow SSH";
type = types.str;
description = "A description for this rule. Restricted to 140 characters.";
};

protocol = mkOption {
example = "Udp";
type = types.enum [ "Tcp" "Udp" "*" ];
description = "Network protocol this rule applies to. Can be Tcp, Udp or * to match both.";
};

sourcePortRange = mkOption {
example = "22";
type = types.str;
description = "Source Port or Range. Integer or range between 0 and 65535 or * to match any.";
};

destinationPortRange = mkOption {
example = "22";
type = types.str;
description = "Destination Port or Range. Integer or range between 0 and 65535 or * to match any.";
};

sourceAddressPrefix = mkOption {
example = "Internet";
type = types.str;
description = ''
CIDR or source IP range or * to match any IP.
Tags such as "VirtualNetwork", "AzureLoadBalancer" and "Internet"
can also be used.
'';
};

destinationAddressPrefix = mkOption {
example = "Internet";
type = types.str;
description = ''
CIDR or destination IP range or * to match any IP.
Tags such as "VirtualNetwork", "AzureLoadBalancer" and "Internet"
can also be used.
'';
};

access = mkOption {
example = "Allow";
type = types.enum [ "Allow" "Deny" ];
description = ''
Specifies whether network traffic is allowed or denied.
Possible values are "Allow" and "Deny".
'';
};

priority = mkOption {
example = 2000;
type = types.int;
description = ''
Specifies the priority of the rule.
The value can be between 100 and 4096.
The priority number must be unique for
each rule in the collection.
The lower the priority number,
the higher the priority of the rule.
'';
};

direction = mkOption {
example = "Inbound";
type = types.enum [ "Inbound" "Outbound" ];
description = ''
The direction specifies if rule will be evaluated
on incoming or outgoing traffic.
Possible values are "Inbound" and "Outbound".
'';
};

};
config = {};
};


in
{

options = (import ./azure-mgmt-credentials.nix lib "network security group") // {

name = mkOption {
default = "nixops-${uuid}-${name}";
example = "my-security-group";
type = types.str;
description = "Name of the Azure network security group.";
};

resourceGroup = mkOption {
example = "xxx-my-group";
type = types.either types.str (resource "azure-resource-group");
description = ''
The name or resource of an Azure resource group
to create the network security group in.
'';
};

location = mkOption {
example = "westus";
type = types.str;
description = ''
The Azure data center location where the
network security group should be created.
'';
};

tags = mkOption {
default = {};
example = { environment = "production"; };
type = types.attrsOf types.str;
description = "Tag name/value pairs to associate with the network security group.";
};

securityRules = mkOption {
default = {};
example = {
allow-ssh = {
description = "Allow SSH";
protocol = "Tcp";
sourcePortRange = "*";
destinationPortRange = "22";
sourceAddressPrefix = "Internet";
destinationAddressPrefix = "*";
access = "Allow";
priority = 2000;
direction = "Inbound";
};
};
type = types.attrsOf types.optionSet;
options = securityRuleOptions;
description = "An attribute set of security rules.";
};

};

config = {
_type = "azure-network-security-group";
resourceGroup = mkDefault resources.azureResourceGroups.def-group;
};

}
11 changes: 11 additions & 0 deletions nix/azure.nix
Expand Up @@ -261,6 +261,17 @@ in
Whether to obtain a dedicated public IP for the interface.
'';
};

securityGroup = mkOption {
default = null;
example = "resources.azureSecurityGroups.my-security-group";
type = types.nullOr (types.either types.str (resource "azure-network-security-group"));
description = ''
The Azure Resource Id or NixOps resource of
the Azure network security group to associate to the interface.
'';
};

};

resourceGroup = mkOption {
Expand Down
1 change: 1 addition & 0 deletions nix/eval-machine-info.nix
Expand Up @@ -107,6 +107,7 @@ rec {
resources.azureDirectories = evalResources ./azure-directory.nix (zipAttrs resourcesByType.azureDirectories or []);
resources.azureFiles = evalResources ./azure-file.nix (zipAttrs resourcesByType.azureFiles or []);
resources.azureLoadBalancers = evalResources ./azure-load-balancer.nix (zipAttrs resourcesByType.azureLoadBalancers or []);
resources.azureSecurityGroups = evalResources ./azure-network-security-group.nix (zipAttrs resourcesByType.azureSecurityGroups or []);
resources.azureQueues = evalResources ./azure-queue.nix (zipAttrs resourcesByType.azureQueues or []);
resources.azureReservedIPAddresses = evalResources ./azure-reserved-ip-address.nix (zipAttrs resourcesByType.azureReservedIPAddresses or []);
resources.azureResourceGroups =
Expand Down
1 change: 1 addition & 0 deletions nixops/azure_common.py
Expand Up @@ -88,6 +88,7 @@ def parse(cls, r_id):
'azure-load-balancer': { 'provider': 'Microsoft.Network', 'type': 'loadBalancers' },
'azure-reserved-ip-address': {'provider': 'Microsoft.Network', 'type': 'publicIPAddresses' },
'azure-virtual-network': {'provider':'Microsoft.Network', 'type': 'virtualNetworks' },
'azure-network-security-group': { 'provider':'Microsoft.Network', 'type': 'networkSecurityGroups' },
}


Expand Down
26 changes: 25 additions & 1 deletion nixops/backends/azure_vm.py
Expand Up @@ -31,6 +31,7 @@
from nixops.resources.azure_directory import AzureDirectoryState
from nixops.resources.azure_file import AzureFileState
from nixops.resources.azure_load_balancer import AzureLoadBalancerState
from nixops.resources.azure_network_security_group import AzureNetworkSecurityGroupState
from nixops.resources.azure_queue import AzureQueueState
from nixops.resources.azure_reserved_ip_address import AzureReservedIPAddressState
from nixops.resources.azure_resource_group import AzureResourceGroupState
Expand Down Expand Up @@ -105,6 +106,7 @@ def __init__(self, xml, config):
ifaces_xml = x.find("attr[@name='networkInterfaces']")
if_xml = ifaces_xml.find("attrs/attr[@name='default']")
self.obtain_ip = self.get_option_value(if_xml, 'obtainIP', bool)
self.copy_option(if_xml, 'securityGroup', 'res-id', optional = True)

subnet_xml = if_xml.find("attrs/attr[@name='subnet']")
self.subnet = ResId(self.get_option_value(subnet_xml, 'network', 'res-id'),
Expand Down Expand Up @@ -206,6 +208,7 @@ def get_type(cls):
resource_group = attr_property("azure.resourceGroup", None)

obtain_ip = attr_property("azure.obtainIP", None, bool)
security_group = attr_property("azure.securityGroup", None)
availability_set = attr_property("azure.availabilitySet", None)

block_device_mapping = attr_property("azure.blockDeviceMapping", {}, 'json')
Expand Down Expand Up @@ -348,6 +351,8 @@ def check_network_iface(self):
iface = None
if iface:
self.handle_changed_property('subnet', iface.ip_configurations[0].subnet.id)
self.handle_changed_property('security_group', iface.network_security_group and
iface.network_security_group.id)
backend_address_pools = [ r.id for r in iface.ip_configurations[0].load_balancer_backend_address_pools ]
self.handle_changed_property('backend_address_pools', sorted(backend_address_pools))
inbound_nat_rules = [ r.id for r in iface.ip_configurations[0].load_balancer_inbound_nat_rules ]
Expand Down Expand Up @@ -662,22 +667,41 @@ def copy_iface_properties(self, defn):
self.backend_address_pools = defn.backend_address_pools
self.inbound_nat_rules = defn.inbound_nat_rules
self.obtain_ip = defn.obtain_ip
self.security_group = defn.security_group
self.subnet = defn.subnet

def iface_properties_changed(self, defn):
return ( self.backend_address_pools != defn.backend_address_pools or
self.inbound_nat_rules != defn.inbound_nat_rules or
self.obtain_ip != defn.obtain_ip or
self.security_group != defn.security_group or
self.subnet != defn.subnet )

def create_or_update_iface(self, defn):
public_ip_id = self.nrpc().public_ip_addresses.get(
self.resource_group,
self.public_ip).public_ip_address.id if defn.obtain_ip else None
print NetworkInterface(name = self.machine_name,
location = defn.location,
network_security_group = defn.security_group and
ResId(defn.security_group),
ip_configurations = [ NetworkInterfaceIpConfiguration(
name = 'default',
private_ip_allocation_method = IpAllocationMethod.dynamic,
subnet = ResId(defn.subnet),
load_balancer_backend_address_pools = [
ResId(pool) for pool in defn.backend_address_pools ],
load_balancer_inbound_nat_rules = [
ResId(rule) for rule in defn.inbound_nat_rules ],
public_ip_address = public_ip_id and ResId(public_ip_id),
)]
).__dict__
self.nrpc().network_interfaces.create_or_update(
self.resource_group, self.machine_name,
NetworkInterface(name = self.machine_name,
location = defn.location,
network_security_group = defn.security_group and
ResId(defn.security_group),
ip_configurations = [ NetworkInterfaceIpConfiguration(
name = 'default',
private_ip_allocation_method = IpAllocationMethod.dynamic,
Expand Down Expand Up @@ -1139,7 +1163,7 @@ def create_after(self, resources, defn):
isinstance(r, AzureDirectoryState) or isinstance(r, AzureFileState) or
isinstance(r, AzureLoadBalancerState) or isinstance(r, AzureQueueState) or
isinstance(r, AzureReservedIPAddressState) or isinstance(r, AzureShareState) or
isinstance(r, AzureTableState)}
isinstance(r, AzureTableState) or isinstance(r, AzureNetworkSecurityGroupState) }

def find_lb_endpoint(self):
for _inr in self.inbound_nat_rules:
Expand Down

0 comments on commit b5d0b1d

Please sign in to comment.