AclMaintainer { public synchronized void converge(NodeAgentContext context) { if (context.isDisabled(NodeAgentTask.AclMaintainer)) return; editFlushOnError(context, IPVersion.IPv4, "filter", FilterTableLineEditor.from(context.acl(), IPVersion.IPv4)); editFlushOnError(context, IPVersion.IPv6, "filter", FilterTableLineEditor.from(context.acl(), IPVersion.IPv6)); ipAddresses.getAddress(context.hostname().value(), IPVersion.IPv4).ifPresent(addr -> applyRedirect(context, addr)); ipAddresses.getAddress(context.hostname().value(), IPVersion.IPv6).ifPresent(addr -> applyRedirect(context, addr)); } AclMaintainer(ContainerOperations containerOperations, IPAddresses ipAddresses); synchronized void converge(NodeAgentContext context);  }
@Test public void configures_full_container_acl_from_empty() { Acl acl = new Acl.Builder().withTrustedPorts(22, 4443) .withTrustedNode("hostname1", "3001::abcd") .withTrustedNode("hostname2", "3001::1234") .withTrustedNode("hostname1", "192.168.0.5") .withTrustedNode("hostname4", "172.16.5.234").build(); NodeAgentContext context = contextGenerator.apply(acl); ipAddresses.addAddress(context.hostname().value(), "2001::1"); ipAddresses.addAddress(context.hostname().value(), "10.0.0.1"); whenListRules(context, "filter", IPVersion.IPv4, EMPTY_FILTER_TABLE); whenListRules(context, "filter", IPVersion.IPv6, EMPTY_FILTER_TABLE); whenListRules(context, "nat", IPVersion.IPv4, EMPTY_NAT_TABLE); whenListRules(context, "nat", IPVersion.IPv6, EMPTY_NAT_TABLE); aclMaintainer.converge(context); verify(containerOperations, times(4)).executeCommandInNetworkNamespace(eq(context), any(), eq("-S"), eq("-t"), any()); verify(containerOperations, times(2)).executeCommandInNetworkNamespace(eq(context), eq("iptables-restore"), any()); verify(containerOperations, times(2)).executeCommandInNetworkNamespace(eq(context), eq("ip6tables-restore"), any()); verifyNoMoreInteractions(containerOperations); List<String> expected = List.of( "*filter\n" + "-P INPUT ACCEPT\n" + "-P FORWARD ACCEPT\n" + "-P OUTPUT ACCEPT\n" + "-A INPUT -m state --state RELATED,ESTABLISHED -j ACCEPT\n" + "-A INPUT -i lo -j ACCEPT\n" + "-A INPUT -p icmp -j ACCEPT\n" + "-A INPUT -p tcp -m multiport --dports 22,4443 -j ACCEPT\n" + "-A INPUT -s 172.16.5.234/32 -j ACCEPT\n" + "-A INPUT -s 192.168.0.5/32 -j ACCEPT\n" + "-A INPUT -j REJECT --reject-with icmp-port-unreachable\n" + "COMMIT\n", "*filter\n" + "-P INPUT ACCEPT\n" + "-P FORWARD ACCEPT\n" + "-P OUTPUT ACCEPT\n" + "-A INPUT -m state --state RELATED,ESTABLISHED -j ACCEPT\n" + "-A INPUT -i lo -j ACCEPT\n" + "-A INPUT -p ipv6-icmp -j ACCEPT\n" + "-A INPUT -p tcp -m multiport --dports 22,4443 -j ACCEPT\n" + "-A INPUT -s 3001::1234/128 -j ACCEPT\n" + "-A INPUT -s 3001::abcd/128 -j ACCEPT\n" + "-A INPUT -j REJECT --reject-with icmp6-port-unreachable\n" + "COMMIT\n", "*nat\n" + "-P PREROUTING ACCEPT\n" + "-P INPUT ACCEPT\n" + "-P OUTPUT ACCEPT\n" + "-P POSTROUTING ACCEPT\n" + "-A OUTPUT -d 10.0.0.1/32 -j REDIRECT\n" + "COMMIT\n", "*nat\n" + "-P PREROUTING ACCEPT\n" + "-P INPUT ACCEPT\n" + "-P OUTPUT ACCEPT\n" + "-P POSTROUTING ACCEPT\n" + "-A OUTPUT -d 2001::1/128 -j REDIRECT\n" + "COMMIT\n"); assertEquals(expected, writtenFileContents); }
@Test public void configures_minimal_container_acl_from_empty() { Acl acl = new Acl.Builder().withTrustedPorts().build(); NodeAgentContext context = contextGenerator.apply(acl); whenListRules(context, "filter", IPVersion.IPv4, EMPTY_FILTER_TABLE); whenListRules(context, "filter", IPVersion.IPv6, EMPTY_FILTER_TABLE); whenListRules(context, "nat", IPVersion.IPv4, EMPTY_NAT_TABLE); whenListRules(context, "nat", IPVersion.IPv6, EMPTY_NAT_TABLE); aclMaintainer.converge(context); verify(containerOperations, times(2)).executeCommandInNetworkNamespace(eq(context), any(), eq("-S"), eq("-t"), any()); verify(containerOperations, times(1)).executeCommandInNetworkNamespace(eq(context), eq("iptables-restore"), any()); verify(containerOperations, times(1)).executeCommandInNetworkNamespace(eq(context), eq("ip6tables-restore"), any()); verifyNoMoreInteractions(containerOperations); List<String> expected = List.of( "*filter\n" + "-P INPUT ACCEPT\n" + "-P FORWARD ACCEPT\n" + "-P OUTPUT ACCEPT\n" + "-A INPUT -m state --state RELATED,ESTABLISHED -j ACCEPT\n" + "-A INPUT -i lo -j ACCEPT\n" + "-A INPUT -p icmp -j ACCEPT\n" + "-A INPUT -j REJECT --reject-with icmp-port-unreachable\n" + "COMMIT\n", "*filter\n" + "-P INPUT ACCEPT\n" + "-P FORWARD ACCEPT\n" + "-P OUTPUT ACCEPT\n" + "-A INPUT -m state --state RELATED,ESTABLISHED -j ACCEPT\n" + "-A INPUT -i lo -j ACCEPT\n" + "-A INPUT -p ipv6-icmp -j ACCEPT\n" + "-A INPUT -j REJECT --reject-with icmp6-port-unreachable\n" + "COMMIT\n"); assertEquals(expected, writtenFileContents); }
@Test public void only_configure_iptables_for_ipversion_that_differs() { Acl acl = new Acl.Builder().withTrustedPorts(22, 4443).withTrustedNode("hostname1", "3001::abcd").build(); NodeAgentContext context = contextGenerator.apply(acl); ipAddresses.addAddress(context.hostname().value(), "2001::1"); whenListRules(context, "filter", IPVersion.IPv4, EMPTY_FILTER_TABLE); whenListRules(context, "filter", IPVersion.IPv6, "-P INPUT ACCEPT\n" + "-P FORWARD ACCEPT\n" + "-P OUTPUT ACCEPT\n" + "-A INPUT -m state --state RELATED,ESTABLISHED -j ACCEPT\n" + "-A INPUT -i lo -j ACCEPT\n" + "-A INPUT -p ipv6-icmp -j ACCEPT\n" + "-A INPUT -p tcp -m multiport --dports 22,4443 -j ACCEPT\n" + "-A INPUT -s 3001::abcd/128 -j ACCEPT\n" + "-A INPUT -j REJECT --reject-with icmp6-port-unreachable\n"); whenListRules(context, "nat", IPVersion.IPv6, "-P PREROUTING ACCEPT\n" + "-P INPUT ACCEPT\n" + "-P OUTPUT ACCEPT\n" + "-P POSTROUTING ACCEPT\n" + "-A OUTPUT -d 2001::1/128 -j REDIRECT\n"); aclMaintainer.converge(context); verify(containerOperations, times(3)).executeCommandInNetworkNamespace(eq(context), any(), eq("-S"), eq("-t"), any()); verify(containerOperations, times(1)).executeCommandInNetworkNamespace(eq(context), eq("iptables-restore"), any()); verify(containerOperations, never()).executeCommandInNetworkNamespace(eq(context), eq("ip6tables-restore"), any()); verifyNoMoreInteractions(containerOperations); List<String> expected = List.of( "*filter\n" + "-P INPUT ACCEPT\n" + "-P FORWARD ACCEPT\n" + "-P OUTPUT ACCEPT\n" + "-A INPUT -m state --state RELATED,ESTABLISHED -j ACCEPT\n" + "-A INPUT -i lo -j ACCEPT\n" + "-A INPUT -p icmp -j ACCEPT\n" + "-A INPUT -p tcp -m multiport --dports 22,4443 -j ACCEPT\n" + "-A INPUT -j REJECT --reject-with icmp-port-unreachable\n" + "COMMIT\n"); assertEquals(expected, writtenFileContents); }
@Test public void rollback_is_attempted_when_applying_acl_fail() { Acl acl = new Acl.Builder().withTrustedPorts(22, 4443).withTrustedNode("hostname1", "3001::abcd").build(); NodeAgentContext context = contextGenerator.apply(acl); ipAddresses.addAddress(context.hostname().value(), "2001::1"); whenListRules(context, "filter", IPVersion.IPv4, EMPTY_FILTER_TABLE); whenListRules(context, "filter", IPVersion.IPv6, "-P INPUT ACCEPT\n" + "-P FORWARD ACCEPT\n" + "-P OUTPUT ACCEPT\n" + "-A INPUT -m state --state RELATED,ESTABLISHED -j ACCEPT\n" + "-A INPUT -i lo -j ACCEPT\n" + "-A INPUT -p ipv6-icmp -j ACCEPT\n" + "-A INPUT -p tcp -m multiport --dports 22,4443 -j ACCEPT\n" + "-A INPUT -s 3001::abcd/128 -j ACCEPT\n" + "-A INPUT -j REJECT --reject-with icmp6-port-unreachable\n"); whenListRules(context, "nat", IPVersion.IPv6, "-P PREROUTING ACCEPT\n" + "-P INPUT ACCEPT\n" + "-P OUTPUT ACCEPT\n" + "-P POSTROUTING ACCEPT\n" + "-A OUTPUT -d 2001::1/128 -j REDIRECT\n"); when(containerOperations.executeCommandInNetworkNamespace(eq(context), eq("iptables-restore"), any())) .thenThrow(new RuntimeException("iptables restore failed")); aclMaintainer.converge(context); verify(containerOperations, times(3)).executeCommandInNetworkNamespace(eq(context), any(), eq("-S"), eq("-t"), any()); verify(containerOperations, times(1)).executeCommandInNetworkNamespace(eq(context), eq("iptables-restore"), any()); verify(containerOperations, times(1)).executeCommandInNetworkNamespace(eq(context), eq("iptables"), eq("-F"), eq("-t"), eq("filter")); verifyNoMoreInteractions(containerOperations); aclMaintainer.converge(context); }