mirror of
https://github.com/apache/cloudstack
synced 2026-08-02 05:26:35 +00:00
Support Firewall for public IPs in VPC (#12706)
This commit is contained in:
parent
f2a1f839a7
commit
13822b1ac1
@ -21,8 +21,13 @@ import java.util.List;
|
|||||||
|
|
||||||
import com.cloud.exception.ResourceUnavailableException;
|
import com.cloud.exception.ResourceUnavailableException;
|
||||||
import com.cloud.network.rules.FirewallRule;
|
import com.cloud.network.rules.FirewallRule;
|
||||||
|
import com.cloud.network.vpc.Vpc;
|
||||||
|
|
||||||
public interface NetworkRuleApplier {
|
public interface NetworkRuleApplier {
|
||||||
public boolean applyRules(Network network, FirewallRule.Purpose purpose, List<? extends FirewallRule> rules) throws ResourceUnavailableException;
|
default boolean applyRules(Network network, FirewallRule.Purpose purpose, List<? extends FirewallRule> rules) throws ResourceUnavailableException {
|
||||||
|
return applyRules(network, null, purpose, rules);
|
||||||
|
}
|
||||||
|
|
||||||
|
boolean applyRules(Network network, Vpc vpc, FirewallRule.Purpose purpose, List<? extends FirewallRule> rules) throws ResourceUnavailableException;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -21,14 +21,20 @@ import java.util.List;
|
|||||||
import com.cloud.exception.ResourceUnavailableException;
|
import com.cloud.exception.ResourceUnavailableException;
|
||||||
import com.cloud.network.Network;
|
import com.cloud.network.Network;
|
||||||
import com.cloud.network.rules.FirewallRule;
|
import com.cloud.network.rules.FirewallRule;
|
||||||
|
import com.cloud.network.vpc.Vpc;
|
||||||
|
|
||||||
public interface FirewallServiceProvider extends NetworkElement {
|
public interface FirewallServiceProvider extends NetworkElement {
|
||||||
/**
|
/**
|
||||||
* Apply rules
|
* Apply firewall rules in a network context.
|
||||||
* @param network
|
|
||||||
* @param rules
|
|
||||||
* @return
|
|
||||||
* @throws ResourceUnavailableException
|
|
||||||
*/
|
*/
|
||||||
boolean applyFWRules(Network network, List<? extends FirewallRule> rules) throws ResourceUnavailableException;
|
default boolean applyFWRules(Network network, List<? extends FirewallRule> rules) throws ResourceUnavailableException {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Apply firewall rules in a VPC context.
|
||||||
|
*/
|
||||||
|
default boolean applyFWRulesInVPC(Vpc vpc, List<? extends FirewallRule> rules) throws ResourceUnavailableException {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -69,7 +69,9 @@ public interface FirewallRule extends ControlledEntity, Identity, InternalIdenti
|
|||||||
|
|
||||||
State getState();
|
State getState();
|
||||||
|
|
||||||
long getNetworkId();
|
Long getNetworkId();
|
||||||
|
|
||||||
|
Long getVpcId();
|
||||||
|
|
||||||
Long getSourceIpAddressId();
|
Long getSourceIpAddressId();
|
||||||
|
|
||||||
|
|||||||
@ -212,7 +212,7 @@ public class CreateEgressFirewallRuleCmd extends BaseAsyncCreateCmd implements F
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public long getNetworkId() {
|
public Long getNetworkId() {
|
||||||
return networkId;
|
return networkId;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -223,13 +223,9 @@ public class CreateFirewallRuleCmd extends BaseAsyncCreateCmd implements Firewal
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public long getNetworkId() {
|
public Long getNetworkId() {
|
||||||
IpAddress ip = _entityMgr.findById(IpAddress.class, getIpAddressId());
|
IpAddress ip = getIp();
|
||||||
Long ntwkId = null;
|
Long ntwkId = isVpcIp(ip) ? getVpcNetworkIdForFirewallRule(ip) : getIsolatedNetworkIdForFirewallRule(ip);
|
||||||
|
|
||||||
if (ip.getAssociatedWithNetworkId() != null) {
|
|
||||||
ntwkId = ip.getAssociatedWithNetworkId();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (ntwkId == null) {
|
if (ntwkId == null) {
|
||||||
throw new InvalidParameterValueException("Unable to create firewall rule for the IP address ID=" + ipAddressId +
|
throw new InvalidParameterValueException("Unable to create firewall rule for the IP address ID=" + ipAddressId +
|
||||||
@ -238,6 +234,12 @@ public class CreateFirewallRuleCmd extends BaseAsyncCreateCmd implements Firewal
|
|||||||
return ntwkId;
|
return ntwkId;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Long getVpcId() {
|
||||||
|
IpAddress ip = getIp();
|
||||||
|
return isVpcIp(ip) ? ip.getVpcId() : null;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public long getEntityOwnerId() {
|
public long getEntityOwnerId() {
|
||||||
Account account = CallContext.current().getCallingAccount();
|
Account account = CallContext.current().getCallingAccount();
|
||||||
@ -300,7 +302,21 @@ public class CreateFirewallRuleCmd extends BaseAsyncCreateCmd implements Firewal
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Long getSyncObjId() {
|
public Long getSyncObjId() {
|
||||||
return getIp().getAssociatedWithNetworkId();
|
Long syncObjId = getIp().getAssociatedWithNetworkId();
|
||||||
|
return syncObjId != null ? syncObjId : getNetworkId();
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean isVpcIp(IpAddress ip) {
|
||||||
|
return ip.getVpcId() != null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private Long getIsolatedNetworkIdForFirewallRule(IpAddress ip) {
|
||||||
|
return ip.getAssociatedWithNetworkId();
|
||||||
|
}
|
||||||
|
|
||||||
|
private Long getVpcNetworkIdForFirewallRule(IpAddress ip) {
|
||||||
|
// VPC flow is independent from tier association; manager resolves execution network.
|
||||||
|
return ip.getNetworkId();
|
||||||
}
|
}
|
||||||
|
|
||||||
private IpAddress getIp() {
|
private IpAddress getIp() {
|
||||||
@ -311,6 +327,7 @@ public class CreateFirewallRuleCmd extends BaseAsyncCreateCmd implements Firewal
|
|||||||
return ip;
|
return ip;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Integer getIcmpCode() {
|
public Integer getIcmpCode() {
|
||||||
if (icmpCode != null) {
|
if (icmpCode != null) {
|
||||||
|
|||||||
@ -176,7 +176,7 @@ public class CreatePortForwardingRuleCmd extends BaseAsyncCreateCmd implements P
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private Long getVpcId() {
|
public Long getVpcId() {
|
||||||
if (ipAddressId != null) {
|
if (ipAddressId != null) {
|
||||||
IpAddress ipAddr = _networkService.getIp(ipAddressId);
|
IpAddress ipAddr = _networkService.getIp(ipAddressId);
|
||||||
if (ipAddr == null || !ipAddr.readyToUse()) {
|
if (ipAddr == null || !ipAddr.readyToUse()) {
|
||||||
@ -275,7 +275,7 @@ public class CreatePortForwardingRuleCmd extends BaseAsyncCreateCmd implements P
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public long getNetworkId() {
|
public Long getNetworkId() {
|
||||||
IpAddress ip = _entityMgr.findById(IpAddress.class, getIpAddressId());
|
IpAddress ip = _entityMgr.findById(IpAddress.class, getIpAddressId());
|
||||||
Long ntwkId = _networkService.getPreferredNetworkIdForPublicIpRuleAssignment(ip, networkId);
|
Long ntwkId = _networkService.getPreferredNetworkIdForPublicIpRuleAssignment(ip, networkId);
|
||||||
if (ntwkId == null) {
|
if (ntwkId == null) {
|
||||||
|
|||||||
@ -229,8 +229,13 @@ public class CreateIpForwardingRuleCmd extends BaseAsyncCreateCmd implements Sta
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public long getNetworkId() {
|
public Long getNetworkId() {
|
||||||
return -1;
|
return -1L;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Long getVpcId() {
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@ -51,6 +51,10 @@ public class FirewallResponse extends BaseResponse {
|
|||||||
@Param(description = "The Network ID of the firewall rule")
|
@Param(description = "The Network ID of the firewall rule")
|
||||||
private String networkId;
|
private String networkId;
|
||||||
|
|
||||||
|
@SerializedName(ApiConstants.VPC_ID)
|
||||||
|
@Param(description = "The VPC ID of the firewall rule")
|
||||||
|
private String vpcId;
|
||||||
|
|
||||||
@SerializedName(ApiConstants.IP_ADDRESS)
|
@SerializedName(ApiConstants.IP_ADDRESS)
|
||||||
@Param(description = "The public IP address for the firewall rule")
|
@Param(description = "The public IP address for the firewall rule")
|
||||||
private String publicIpAddress;
|
private String publicIpAddress;
|
||||||
@ -115,6 +119,10 @@ public class FirewallResponse extends BaseResponse {
|
|||||||
this.networkId = networkId;
|
this.networkId = networkId;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void setVpcId(String vpcId) {
|
||||||
|
this.vpcId = vpcId;
|
||||||
|
}
|
||||||
|
|
||||||
public void setState(String state) {
|
public void setState(String state) {
|
||||||
this.state = state;
|
this.state = state;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -21,10 +21,15 @@ import java.util.Arrays;
|
|||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
|
import com.cloud.network.IpAddress;
|
||||||
|
import com.cloud.network.NetworkService;
|
||||||
|
import com.cloud.utils.db.EntityManager;
|
||||||
import org.apache.commons.collections.CollectionUtils;
|
import org.apache.commons.collections.CollectionUtils;
|
||||||
import org.junit.Assert;
|
import org.junit.Assert;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
import org.junit.runner.RunWith;
|
import org.junit.runner.RunWith;
|
||||||
|
import org.mockito.Mock;
|
||||||
|
import org.mockito.Mockito;
|
||||||
import org.mockito.junit.MockitoJUnitRunner;
|
import org.mockito.junit.MockitoJUnitRunner;
|
||||||
import org.springframework.test.util.ReflectionTestUtils;
|
import org.springframework.test.util.ReflectionTestUtils;
|
||||||
|
|
||||||
@ -33,6 +38,12 @@ import com.cloud.utils.net.NetUtils;
|
|||||||
@RunWith(MockitoJUnitRunner.class)
|
@RunWith(MockitoJUnitRunner.class)
|
||||||
public class CreateFirewallRuleCmdTest {
|
public class CreateFirewallRuleCmdTest {
|
||||||
|
|
||||||
|
@Mock
|
||||||
|
private EntityManager entityManager;
|
||||||
|
|
||||||
|
@Mock
|
||||||
|
private NetworkService networkService;
|
||||||
|
|
||||||
private void validateAllIp4Cidr(final CreateFirewallRuleCmd cmd) {
|
private void validateAllIp4Cidr(final CreateFirewallRuleCmd cmd) {
|
||||||
Assert.assertTrue(CollectionUtils.isNotEmpty(cmd.getSourceCidrList()));
|
Assert.assertTrue(CollectionUtils.isNotEmpty(cmd.getSourceCidrList()));
|
||||||
Assert.assertEquals(1, cmd.getSourceCidrList().size());
|
Assert.assertEquals(1, cmd.getSourceCidrList().size());
|
||||||
@ -88,4 +99,22 @@ public class CreateFirewallRuleCmdTest {
|
|||||||
Assert.assertEquals(2, cmd.getSourceCidrList().size());
|
Assert.assertEquals(2, cmd.getSourceCidrList().size());
|
||||||
Assert.assertEquals(cidr, cmd.getSourceCidrList().get(1));
|
Assert.assertEquals(cidr, cmd.getSourceCidrList().get(1));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testGetNetworkIdVpcWithoutAssociatedNetworkUsesVpcFallbackAndSyncObjId() {
|
||||||
|
final CreateFirewallRuleCmd cmd = new CreateFirewallRuleCmd();
|
||||||
|
final IpAddress ip = Mockito.mock(IpAddress.class);
|
||||||
|
|
||||||
|
cmd._entityMgr = entityManager;
|
||||||
|
cmd._networkService = networkService;
|
||||||
|
ReflectionTestUtils.setField(cmd, "ipAddressId", 42L);
|
||||||
|
|
||||||
|
Mockito.when(networkService.getIp(42L)).thenReturn(ip);
|
||||||
|
Mockito.when(ip.getAssociatedWithNetworkId()).thenReturn(null);
|
||||||
|
Mockito.when(ip.getVpcId()).thenReturn(100L);
|
||||||
|
Mockito.when(ip.getNetworkId()).thenReturn(2L);
|
||||||
|
|
||||||
|
Assert.assertEquals(Long.valueOf(2L), cmd.getNetworkId());
|
||||||
|
Assert.assertEquals(Long.valueOf(2L), cmd.getSyncObjId());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -37,6 +37,7 @@ public abstract class NetworkElementCommand extends Command {
|
|||||||
public static final String ZONE_NETWORK_TYPE = "zone.network.type";
|
public static final String ZONE_NETWORK_TYPE = "zone.network.type";
|
||||||
public static final String GUEST_BRIDGE = "guest.bridge";
|
public static final String GUEST_BRIDGE = "guest.bridge";
|
||||||
public static final String VPC_PRIVATE_GATEWAY = "vpc.gateway.private";
|
public static final String VPC_PRIVATE_GATEWAY = "vpc.gateway.private";
|
||||||
|
public static final String VPC_ID = "vpc.id";
|
||||||
public static final String FIREWALL_EGRESS_DEFAULT = "firewall.egress.default";
|
public static final String FIREWALL_EGRESS_DEFAULT = "firewall.egress.default";
|
||||||
public static final String NETWORK_PUB_LAST_IP = "network.public.last.ip";
|
public static final String NETWORK_PUB_LAST_IP = "network.public.last.ip";
|
||||||
public static final String HYPERVISOR_HOST_PRIVATE_IP = "hypervisor.private.ip";
|
public static final String HYPERVISOR_HOST_PRIVATE_IP = "hypervisor.private.ip";
|
||||||
|
|||||||
@ -32,6 +32,7 @@ import java.util.Set;
|
|||||||
*/
|
*/
|
||||||
public class SetFirewallRulesCommand extends NetworkElementCommand {
|
public class SetFirewallRulesCommand extends NetworkElementCommand {
|
||||||
FirewallRuleTO[] rules;
|
FirewallRuleTO[] rules;
|
||||||
|
Long vpcId;
|
||||||
|
|
||||||
protected SetFirewallRulesCommand() {
|
protected SetFirewallRulesCommand() {
|
||||||
}
|
}
|
||||||
@ -40,10 +41,19 @@ public class SetFirewallRulesCommand extends NetworkElementCommand {
|
|||||||
this.rules = rules.toArray(new FirewallRuleTO[rules.size()]);
|
this.rules = rules.toArray(new FirewallRuleTO[rules.size()]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public SetFirewallRulesCommand(List<FirewallRuleTO> rules, Long vpcId) {
|
||||||
|
this.rules = rules.toArray(new FirewallRuleTO[rules.size()]);
|
||||||
|
this.vpcId = vpcId;
|
||||||
|
}
|
||||||
|
|
||||||
public FirewallRuleTO[] getRules() {
|
public FirewallRuleTO[] getRules() {
|
||||||
return rules;
|
return rules;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Long getVpcId() {
|
||||||
|
return vpcId;
|
||||||
|
}
|
||||||
|
|
||||||
public String[][] generateFwRules() {
|
public String[][] generateFwRules() {
|
||||||
String[][] result = new String[2][];
|
String[][] result = new String[2][];
|
||||||
Set<String> toAdd = new HashSet<String>();
|
Set<String> toAdd = new HashSet<String>();
|
||||||
|
|||||||
@ -80,10 +80,15 @@ public class StaticNatRuleImpl implements StaticNatRule {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public long getNetworkId() {
|
public Long getNetworkId() {
|
||||||
return networkId;
|
return networkId;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Long getVpcId() {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public long getId() {
|
public long getId() {
|
||||||
return id;
|
return id;
|
||||||
|
|||||||
@ -593,6 +593,7 @@ public class NetworkOrchestrator extends ManagerBase implements NetworkOrchestra
|
|||||||
defaultVPCOffProviders.put(Service.StaticNat, defaultProviders);
|
defaultVPCOffProviders.put(Service.StaticNat, defaultProviders);
|
||||||
defaultVPCOffProviders.put(Service.PortForwarding, defaultProviders);
|
defaultVPCOffProviders.put(Service.PortForwarding, defaultProviders);
|
||||||
defaultVPCOffProviders.put(Service.Vpn, defaultProviders);
|
defaultVPCOffProviders.put(Service.Vpn, defaultProviders);
|
||||||
|
defaultVPCOffProviders.put(Service.Firewall, defaultProviders);
|
||||||
|
|
||||||
Transaction.execute(new TransactionCallbackNoReturn() {
|
Transaction.execute(new TransactionCallbackNoReturn() {
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@ -69,6 +69,8 @@ public interface FirewallRulesDao extends GenericDao<FirewallRuleVO, Long> {
|
|||||||
|
|
||||||
List<FirewallRuleVO> listByNetworkPurposeTrafficType(long networkId, FirewallRule.Purpose purpose, FirewallRule.TrafficType trafficType);
|
List<FirewallRuleVO> listByNetworkPurposeTrafficType(long networkId, FirewallRule.Purpose purpose, FirewallRule.TrafficType trafficType);
|
||||||
|
|
||||||
|
List<FirewallRuleVO> listByVpcPurposeTrafficType(long vpcId, FirewallRule.Purpose purpose, FirewallRule.TrafficType trafficType);
|
||||||
|
|
||||||
List<FirewallRuleVO> listByIpAndPurposeWithState(Long addressId, FirewallRule.Purpose purpose, FirewallRule.State state);
|
List<FirewallRuleVO> listByIpAndPurposeWithState(Long addressId, FirewallRule.Purpose purpose, FirewallRule.State state);
|
||||||
|
|
||||||
void loadSourceCidrs(FirewallRuleVO rule);
|
void loadSourceCidrs(FirewallRuleVO rule);
|
||||||
|
|||||||
@ -74,6 +74,7 @@ public class FirewallRulesDaoImpl extends GenericDaoBase<FirewallRuleVO, Long> i
|
|||||||
AllFieldsSearch.and("domain", AllFieldsSearch.entity().getDomainId(), Op.EQ);
|
AllFieldsSearch.and("domain", AllFieldsSearch.entity().getDomainId(), Op.EQ);
|
||||||
AllFieldsSearch.and("id", AllFieldsSearch.entity().getId(), Op.EQ);
|
AllFieldsSearch.and("id", AllFieldsSearch.entity().getId(), Op.EQ);
|
||||||
AllFieldsSearch.and("networkId", AllFieldsSearch.entity().getNetworkId(), Op.EQ);
|
AllFieldsSearch.and("networkId", AllFieldsSearch.entity().getNetworkId(), Op.EQ);
|
||||||
|
AllFieldsSearch.and("vpcId", AllFieldsSearch.entity().getVpcId(), Op.EQ);
|
||||||
AllFieldsSearch.and("related", AllFieldsSearch.entity().getRelated(), Op.EQ);
|
AllFieldsSearch.and("related", AllFieldsSearch.entity().getRelated(), Op.EQ);
|
||||||
AllFieldsSearch.and("trafficType", AllFieldsSearch.entity().getTrafficType(), Op.EQ);
|
AllFieldsSearch.and("trafficType", AllFieldsSearch.entity().getTrafficType(), Op.EQ);
|
||||||
AllFieldsSearch.done();
|
AllFieldsSearch.done();
|
||||||
@ -356,6 +357,22 @@ public class FirewallRulesDaoImpl extends GenericDaoBase<FirewallRuleVO, Long> i
|
|||||||
return listBy(sc);
|
return listBy(sc);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<FirewallRuleVO> listByVpcPurposeTrafficType(long vpcId, Purpose purpose, TrafficType trafficType) {
|
||||||
|
SearchCriteria<FirewallRuleVO> sc = AllFieldsSearch.create();
|
||||||
|
sc.setParameters("vpcId", vpcId);
|
||||||
|
|
||||||
|
if (purpose != null) {
|
||||||
|
sc.setParameters("purpose", purpose);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (trafficType != null) {
|
||||||
|
sc.setParameters("trafficType", trafficType);
|
||||||
|
}
|
||||||
|
|
||||||
|
return listBy(sc);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@DB
|
@DB
|
||||||
public boolean remove(Long id) {
|
public boolean remove(Long id) {
|
||||||
|
|||||||
@ -91,6 +91,9 @@ public class FirewallRuleVO implements FirewallRule {
|
|||||||
@Column(name = "network_id")
|
@Column(name = "network_id")
|
||||||
Long networkId;
|
Long networkId;
|
||||||
|
|
||||||
|
@Column(name = "vpc_id")
|
||||||
|
Long vpcId;
|
||||||
|
|
||||||
@Column(name = "icmp_code")
|
@Column(name = "icmp_code")
|
||||||
Integer icmpCode;
|
Integer icmpCode;
|
||||||
|
|
||||||
@ -196,10 +199,18 @@ public class FirewallRuleVO implements FirewallRule {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public long getNetworkId() {
|
public Long getNetworkId() {
|
||||||
return networkId;
|
return networkId;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Long getVpcId() {
|
||||||
|
return vpcId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setVpcId(Long vpcId) {
|
||||||
|
this.vpcId = vpcId;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public FirewallRuleType getType() {
|
public FirewallRuleType getType() {
|
||||||
return type;
|
return type;
|
||||||
@ -217,7 +228,7 @@ public class FirewallRuleVO implements FirewallRule {
|
|||||||
uuid = UUID.randomUUID().toString();
|
uuid = UUID.randomUUID().toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
public FirewallRuleVO(String xId, Long ipAddressId, Integer portStart, Integer portEnd, String protocol, long networkId, long accountId, long domainId,
|
public FirewallRuleVO(String xId, Long ipAddressId, Integer portStart, Integer portEnd, String protocol, Long networkId, long accountId, long domainId,
|
||||||
Purpose purpose, List<String> sourceCidrs, Integer icmpCode, Integer icmpType, Long related, TrafficType trafficType) {
|
Purpose purpose, List<String> sourceCidrs, Integer icmpCode, Integer icmpType, Long related, TrafficType trafficType) {
|
||||||
this.xId = xId;
|
this.xId = xId;
|
||||||
if (xId == null) {
|
if (xId == null) {
|
||||||
@ -261,7 +272,7 @@ public class FirewallRuleVO implements FirewallRule {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public FirewallRuleVO(String xId, Long ipAddressId, Integer portStart, Integer portEnd, String protocol, long networkId, long accountId, long domainId,
|
public FirewallRuleVO(String xId, Long ipAddressId, Integer portStart, Integer portEnd, String protocol, Long networkId, long accountId, long domainId,
|
||||||
Purpose purpose, List<String> sourceCidrs, List<String> destCidrs, Integer icmpCode, Integer icmpType, Long related, TrafficType trafficType) {
|
Purpose purpose, List<String> sourceCidrs, List<String> destCidrs, Integer icmpCode, Integer icmpType, Long related, TrafficType trafficType) {
|
||||||
this(xId,ipAddressId, portStart, portEnd, protocol, networkId, accountId, domainId, purpose, sourceCidrs, icmpCode, icmpType, related, trafficType);
|
this(xId,ipAddressId, portStart, portEnd, protocol, networkId, accountId, domainId, purpose, sourceCidrs, icmpCode, icmpType, related, trafficType);
|
||||||
this.destinationCidrs = destCidrs;
|
this.destinationCidrs = destCidrs;
|
||||||
|
|||||||
@ -588,3 +588,6 @@ CREATE TABLE IF NOT EXISTS `cloud`.`dns_zone_network_map` (
|
|||||||
CONSTRAINT `fk_dns_map__zone_id` FOREIGN KEY (`dns_zone_id`) REFERENCES `dns_zone` (`id`) ON DELETE CASCADE,
|
CONSTRAINT `fk_dns_map__zone_id` FOREIGN KEY (`dns_zone_id`) REFERENCES `dns_zone` (`id`) ON DELETE CASCADE,
|
||||||
CONSTRAINT `fk_dns_map__network_id` FOREIGN KEY (`network_id`) REFERENCES `networks` (`id`) ON DELETE CASCADE
|
CONSTRAINT `fk_dns_map__network_id` FOREIGN KEY (`network_id`) REFERENCES `networks` (`id`) ON DELETE CASCADE
|
||||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
|
||||||
|
|
||||||
|
-- This is part of allowing firewall rules on public IP addresses in VPC network
|
||||||
|
ALTER TABLE `cloud`.`firewall_rules` MODIFY COLUMN `network_id` BIGINT UNSIGNED NULL;
|
||||||
|
|||||||
@ -2986,9 +2986,8 @@ public class KubernetesClusterManagerImpl extends ManagerBase implements Kuberne
|
|||||||
defaultKubernetesServiceNetworkOfferingProviders.put(Service.UserData, provider);
|
defaultKubernetesServiceNetworkOfferingProviders.put(Service.UserData, provider);
|
||||||
if (forVpc) {
|
if (forVpc) {
|
||||||
defaultKubernetesServiceNetworkOfferingProviders.put(Service.NetworkACL, forNsx ? Network.Provider.Nsx : provider);
|
defaultKubernetesServiceNetworkOfferingProviders.put(Service.NetworkACL, forNsx ? Network.Provider.Nsx : provider);
|
||||||
} else {
|
|
||||||
defaultKubernetesServiceNetworkOfferingProviders.put(Service.Firewall, forNsx ? Network.Provider.Nsx : provider);
|
|
||||||
}
|
}
|
||||||
|
defaultKubernetesServiceNetworkOfferingProviders.put(Service.Firewall, forNsx ? Network.Provider.Nsx : provider);
|
||||||
defaultKubernetesServiceNetworkOfferingProviders.put(Service.Lb, forNsx ? Network.Provider.Nsx : provider);
|
defaultKubernetesServiceNetworkOfferingProviders.put(Service.Lb, forNsx ? Network.Provider.Nsx : provider);
|
||||||
defaultKubernetesServiceNetworkOfferingProviders.put(Service.SourceNat, forNsx ? Network.Provider.Nsx : provider);
|
defaultKubernetesServiceNetworkOfferingProviders.put(Service.SourceNat, forNsx ? Network.Provider.Nsx : provider);
|
||||||
defaultKubernetesServiceNetworkOfferingProviders.put(Service.StaticNat, forNsx ? Network.Provider.Nsx : provider);
|
defaultKubernetesServiceNetworkOfferingProviders.put(Service.StaticNat, forNsx ? Network.Provider.Nsx : provider);
|
||||||
|
|||||||
@ -155,7 +155,7 @@ public class KubernetesClusterManagerImplTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private FirewallRuleVO createRule(int startPort, int endPort) {
|
private FirewallRuleVO createRule(int startPort, int endPort) {
|
||||||
FirewallRuleVO rule = new FirewallRuleVO(null, null, startPort, endPort, "tcp", 1, 1, 1, FirewallRule.Purpose.Firewall, List.of("0.0.0.0/0"), null, null, null, FirewallRule.TrafficType.Ingress);
|
FirewallRuleVO rule = new FirewallRuleVO(null, null, startPort, endPort, "tcp", 1L, 1, 1, FirewallRule.Purpose.Firewall, List.of("0.0.0.0/0"), null, null, null, FirewallRule.TrafficType.Ingress);
|
||||||
return rule;
|
return rule;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -290,7 +290,7 @@ public class PaloAltoResourceTest {
|
|||||||
List<FirewallRuleTO> rules = new ArrayList<FirewallRuleTO>();
|
List<FirewallRuleTO> rules = new ArrayList<FirewallRuleTO>();
|
||||||
List<String> cidrList = new ArrayList<String>();
|
List<String> cidrList = new ArrayList<String>();
|
||||||
cidrList.add("0.0.0.0/0");
|
cidrList.add("0.0.0.0/0");
|
||||||
FirewallRuleVO activeVO = new FirewallRuleVO(null, null, 80, 80, "tcp", 1, 1, 1, Purpose.Firewall, cidrList, null, null, null, FirewallRule.TrafficType.Egress);
|
FirewallRuleVO activeVO = new FirewallRuleVO(null, null, 80, 80, "tcp", 1L, 1, 1, Purpose.Firewall, cidrList, null, null, null, FirewallRule.TrafficType.Egress);
|
||||||
FirewallRuleTO active = new FirewallRuleTO(activeVO, Long.toString(vlanId), null, Purpose.Firewall, FirewallRule.TrafficType.Egress);
|
FirewallRuleTO active = new FirewallRuleTO(activeVO, Long.toString(vlanId), null, Purpose.Firewall, FirewallRule.TrafficType.Egress);
|
||||||
rules.add(active);
|
rules.add(active);
|
||||||
|
|
||||||
@ -319,7 +319,7 @@ public class PaloAltoResourceTest {
|
|||||||
|
|
||||||
long vlanId = 3954;
|
long vlanId = 3954;
|
||||||
List<FirewallRuleTO> rules = new ArrayList<FirewallRuleTO>();
|
List<FirewallRuleTO> rules = new ArrayList<FirewallRuleTO>();
|
||||||
FirewallRuleVO revokedVO = new FirewallRuleVO(null, null, 80, 80, "tcp", 1, 1, 1, Purpose.Firewall, null, null, null, null, FirewallRule.TrafficType.Egress);
|
FirewallRuleVO revokedVO = new FirewallRuleVO(null, null, 80, 80, "tcp", 1L, 1, 1, Purpose.Firewall, null, null, null, null, FirewallRule.TrafficType.Egress);
|
||||||
revokedVO.setState(State.Revoke);
|
revokedVO.setState(State.Revoke);
|
||||||
FirewallRuleTO revoked = new FirewallRuleTO(revokedVO, Long.toString(vlanId), null, Purpose.Firewall, FirewallRule.TrafficType.Egress);
|
FirewallRuleTO revoked = new FirewallRuleTO(revokedVO, Long.toString(vlanId), null, Purpose.Firewall, FirewallRule.TrafficType.Egress);
|
||||||
rules.add(revoked);
|
rules.add(revoked);
|
||||||
|
|||||||
@ -2968,8 +2968,21 @@ public class ApiResponseHelper implements ResponseGenerator, ResourceIdSupport {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Network network = ApiDBUtils.findNetworkById(fwRule.getNetworkId());
|
Long networkId = fwRule.getNetworkId();
|
||||||
response.setNetworkId(network.getUuid());
|
if (networkId != null) {
|
||||||
|
Network network = ApiDBUtils.findNetworkById(networkId);
|
||||||
|
if (network != null) {
|
||||||
|
response.setNetworkId(network.getUuid());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Long vpcId = fwRule.getVpcId();
|
||||||
|
if (vpcId != null) {
|
||||||
|
Vpc vpc = ApiDBUtils.findVpcById(vpcId);
|
||||||
|
if (vpc != null) {
|
||||||
|
response.setVpcId(vpc.getUuid());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
FirewallRule.State state = fwRule.getState();
|
FirewallRule.State state = fwRule.getState();
|
||||||
String stateToSet = state.toString();
|
String stateToSet = state.toString();
|
||||||
@ -5420,8 +5433,21 @@ public class ApiResponseHelper implements ResponseGenerator, ResourceIdSupport {
|
|||||||
response.setIcmpCode(fwRule.getIcmpCode());
|
response.setIcmpCode(fwRule.getIcmpCode());
|
||||||
response.setIcmpType(fwRule.getIcmpType());
|
response.setIcmpType(fwRule.getIcmpType());
|
||||||
|
|
||||||
Network network = ApiDBUtils.findNetworkById(fwRule.getNetworkId());
|
Long networkId = fwRule.getNetworkId();
|
||||||
response.setNetworkId(network.getUuid());
|
if (networkId != null) {
|
||||||
|
Network network = ApiDBUtils.findNetworkById(networkId);
|
||||||
|
if (network != null) {
|
||||||
|
response.setNetworkId(network.getUuid());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Long vpcId = fwRule.getVpcId();
|
||||||
|
if (vpcId != null) {
|
||||||
|
Vpc vpc = ApiDBUtils.findVpcById(vpcId);
|
||||||
|
if (vpc != null) {
|
||||||
|
response.setVpcId(vpc.getUuid());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
FirewallRule.State state = fwRule.getState();
|
FirewallRule.State state = fwRule.getState();
|
||||||
String stateToSet = state.toString();
|
String stateToSet = state.toString();
|
||||||
|
|||||||
@ -7263,10 +7263,12 @@ public class ConfigurationManagerImpl extends ManagerBase implements Configurati
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (forVpc == null) {
|
if (forVpc == null) {
|
||||||
if (service == Service.SecurityGroup || service == Service.Firewall) {
|
if (service == Service.SecurityGroup) {
|
||||||
forVpc = false;
|
forVpc = false;
|
||||||
} else if (service == Service.NetworkACL) {
|
} else if (service == Service.NetworkACL) {
|
||||||
forVpc = true;
|
forVpc = true;
|
||||||
|
} else if (service == Service.Firewall) {
|
||||||
|
forVpc = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -659,28 +659,58 @@ public class IpAddressManagerImpl extends ManagerBase implements IpAddressManage
|
|||||||
}
|
}
|
||||||
|
|
||||||
boolean success = true;
|
boolean success = true;
|
||||||
Network network = _networksDao.findById(rules.get(0).getNetworkId());
|
FirewallRule firstRule = rules.get(0);
|
||||||
FirewallRuleVO.TrafficType trafficType = rules.get(0).getTrafficType();
|
Long networkId = firstRule.getNetworkId();
|
||||||
|
Long vpcId = firstRule.getVpcId();
|
||||||
|
FirewallRuleVO.TrafficType trafficType = firstRule.getTrafficType();
|
||||||
List<PublicIp> publicIps = new ArrayList<PublicIp>();
|
List<PublicIp> publicIps = new ArrayList<PublicIp>();
|
||||||
|
|
||||||
if (!(rules.get(0).getPurpose() == FirewallRule.Purpose.Firewall && trafficType == FirewallRule.TrafficType.Egress)) {
|
// For VPC firewall rules the networkId on the rule is null; resolve via VPC.
|
||||||
// get the list of public ip's owned by the network
|
Network network = null;
|
||||||
List<IPAddressVO> userIps = _ipAddressDao.listByAssociatedNetwork(network.getId(), null);
|
Vpc vpc = null;
|
||||||
if (userIps != null && !userIps.isEmpty()) {
|
if (networkId != null) {
|
||||||
for (IPAddressVO userIp : userIps) {
|
network = _networksDao.findById(networkId);
|
||||||
PublicIp publicIp = PublicIp.createFromAddrAndVlan(userIp, _vlanDao.findById(userIp.getVlanId()));
|
} else if (vpcId != null) {
|
||||||
publicIps.add(publicIp);
|
vpc = _vpcDao.findById(vpcId);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (network == null) {
|
||||||
|
logger.warn("Unable to resolve network for firewall rules (networkId={}, vpcId={}); skipping IP association", networkId, vpcId);
|
||||||
|
} else if (!(firstRule.getPurpose() == FirewallRule.Purpose.Firewall && trafficType == FirewallRule.TrafficType.Egress)) {
|
||||||
|
// For VPC ingress rules, collect public IPs tied to the VPC rather than network association
|
||||||
|
if (vpcId != null && networkId == null) {
|
||||||
|
List<IPAddressVO> vpcIps = _ipAddressDao.listByAssociatedVpc(vpcId, null);
|
||||||
|
if (vpcIps != null) {
|
||||||
|
for (IPAddressVO userIp : vpcIps) {
|
||||||
|
PublicIp publicIp = PublicIp.createFromAddrAndVlan(userIp, _vlanDao.findById(userIp.getVlanId()));
|
||||||
|
publicIps.add(publicIp);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// get the list of public ip's owned by the network
|
||||||
|
List<IPAddressVO> userIps = _ipAddressDao.listByAssociatedNetwork(network.getId(), null);
|
||||||
|
if (userIps != null && !userIps.isEmpty()) {
|
||||||
|
for (IPAddressVO userIp : userIps) {
|
||||||
|
PublicIp publicIp = PublicIp.createFromAddrAndVlan(userIp, _vlanDao.findById(userIp.getVlanId()));
|
||||||
|
publicIps.add(publicIp);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// rules can not programmed unless IP is associated with network service provider, so run IP assoication for
|
|
||||||
|
// rules can not programmed unless IP is associated with network service provider, so run IP association for
|
||||||
// the network so as to ensure IP is associated before applying rules (in add state)
|
// the network so as to ensure IP is associated before applying rules (in add state)
|
||||||
if (checkIfIpAssocRequired(network, false, publicIps)) {
|
if (network != null && checkIfIpAssocRequired(network, false, publicIps)) {
|
||||||
applyIpAssociations(network, false, continueOnError, publicIps);
|
applyIpAssociations(network, false, continueOnError, publicIps);
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
applier.applyRules(network, purpose, rules);
|
if (network != null || vpc != null) {
|
||||||
|
applier.applyRules(network, vpc, purpose, rules);
|
||||||
|
} else {
|
||||||
|
logger.warn("Skipping applyRules: no network or vpc resolved for rules (networkId={}, vpcId={})", networkId, vpcId);
|
||||||
|
success = false;
|
||||||
|
}
|
||||||
} catch (ResourceUnavailableException e) {
|
} catch (ResourceUnavailableException e) {
|
||||||
if (!continueOnError) {
|
if (!continueOnError) {
|
||||||
throw e;
|
throw e;
|
||||||
@ -691,7 +721,7 @@ public class IpAddressManagerImpl extends ManagerBase implements IpAddressManage
|
|||||||
|
|
||||||
// if there are no active rules associated with a public IP, then public IP need not be associated with a provider.
|
// if there are no active rules associated with a public IP, then public IP need not be associated with a provider.
|
||||||
// This IPAssoc ensures, public IP is dis-associated after last active rule is revoked.
|
// This IPAssoc ensures, public IP is dis-associated after last active rule is revoked.
|
||||||
if (checkIfIpAssocRequired(network, true, publicIps)) {
|
if (network != null && checkIfIpAssocRequired(network, true, publicIps)) {
|
||||||
applyIpAssociations(network, true, continueOnError, publicIps);
|
applyIpAssociations(network, true, continueOnError, publicIps);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -107,9 +107,11 @@ import com.cloud.network.rules.FirewallRuleVO;
|
|||||||
import com.cloud.network.rules.dao.PortForwardingRulesDao;
|
import com.cloud.network.rules.dao.PortForwardingRulesDao;
|
||||||
import com.cloud.network.vpc.Vpc;
|
import com.cloud.network.vpc.Vpc;
|
||||||
import com.cloud.network.vpc.VpcGatewayVO;
|
import com.cloud.network.vpc.VpcGatewayVO;
|
||||||
|
import com.cloud.network.vpc.VpcOfferingServiceMapVO;
|
||||||
import com.cloud.network.vpc.dao.PrivateIpDao;
|
import com.cloud.network.vpc.dao.PrivateIpDao;
|
||||||
import com.cloud.network.vpc.dao.VpcDao;
|
import com.cloud.network.vpc.dao.VpcDao;
|
||||||
import com.cloud.network.vpc.dao.VpcGatewayDao;
|
import com.cloud.network.vpc.dao.VpcGatewayDao;
|
||||||
|
import com.cloud.network.vpc.dao.VpcOfferingServiceMapDao;
|
||||||
import com.cloud.offering.NetworkOffering;
|
import com.cloud.offering.NetworkOffering;
|
||||||
import com.cloud.offering.NetworkOffering.Detail;
|
import com.cloud.offering.NetworkOffering.Detail;
|
||||||
import com.cloud.offerings.NetworkOfferingServiceMapVO;
|
import com.cloud.offerings.NetworkOfferingServiceMapVO;
|
||||||
@ -186,6 +188,8 @@ public class NetworkModelImpl extends ManagerBase implements NetworkModel, Confi
|
|||||||
NetworkPermissionDao _networkPermissionDao;
|
NetworkPermissionDao _networkPermissionDao;
|
||||||
@Inject
|
@Inject
|
||||||
VpcDao vpcDao;
|
VpcDao vpcDao;
|
||||||
|
@Inject
|
||||||
|
VpcOfferingServiceMapDao _vpcOffSvcMapDao;
|
||||||
|
|
||||||
private List<NetworkElement> networkElements;
|
private List<NetworkElement> networkElements;
|
||||||
|
|
||||||
@ -510,12 +514,16 @@ public class NetworkModelImpl extends ManagerBase implements NetworkModel, Confi
|
|||||||
// We only support one provider for one service now
|
// We only support one provider for one service now
|
||||||
Map<Service, Set<Provider>> serviceToProviders = getServiceProvidersMap(networkId);
|
Map<Service, Set<Provider>> serviceToProviders = getServiceProvidersMap(networkId);
|
||||||
// Since IP already has service to bind with, the oldProvider can't be null
|
// Since IP already has service to bind with, the oldProvider can't be null
|
||||||
Set<Provider> newProviders = serviceToProviders.get(service);
|
Set<Provider> newProviders = getProvidersForServiceWithVpcFallback(serviceToProviders, service, publicIp.getVpcId());
|
||||||
if (newProviders == null || newProviders.isEmpty()) {
|
if (newProviders == null || newProviders.isEmpty()) {
|
||||||
throw new InvalidParameterValueException("There is no new provider for IP " + publicIp.getAddress() + " of service " + service.getName() + "!");
|
throw new InvalidParameterValueException("There is no new provider for IP " + publicIp.getAddress() + " of service " + service.getName() + "!");
|
||||||
}
|
}
|
||||||
Provider newProvider = (Provider)newProviders.toArray()[0];
|
Provider newProvider = (Provider)newProviders.toArray()[0];
|
||||||
Set<Provider> oldProviders = serviceToProviders.get(services.toArray()[0]);
|
Service existingService = (Service) services.toArray()[0];
|
||||||
|
Set<Provider> oldProviders = getProvidersForServiceWithVpcFallback(serviceToProviders, existingService, publicIp.getVpcId());
|
||||||
|
if (oldProviders == null || oldProviders.isEmpty()) {
|
||||||
|
throw new InvalidParameterValueException("There is no existing provider for IP " + publicIp.getAddress() + " of service " + existingService.getName() + "!");
|
||||||
|
}
|
||||||
Provider oldProvider = (Provider)oldProviders.toArray()[0];
|
Provider oldProvider = (Provider)oldProviders.toArray()[0];
|
||||||
Network network = _networksDao.findById(networkId);
|
Network network = _networksDao.findById(networkId);
|
||||||
NetworkElement oldElement = getElementImplementingProvider(oldProvider.getName());
|
NetworkElement oldElement = getElementImplementingProvider(oldProvider.getName());
|
||||||
@ -530,6 +538,35 @@ public class NetworkModelImpl extends ManagerBase implements NetworkModel, Confi
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private Set<Provider> getProvidersForServiceWithVpcFallback(Map<Service, Set<Provider>> serviceToProviders, Service service, Long vpcId) {
|
||||||
|
Set<Provider> providers = serviceToProviders.get(service);
|
||||||
|
if (providers != null && !providers.isEmpty()) {
|
||||||
|
return providers;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (vpcId == null || service != Service.Firewall) {
|
||||||
|
return providers;
|
||||||
|
}
|
||||||
|
|
||||||
|
Set<Provider> vpcProviders = new HashSet<Provider>();
|
||||||
|
Vpc vpc = vpcDao.findById(vpcId);
|
||||||
|
if (vpc == null) {
|
||||||
|
return vpcProviders;
|
||||||
|
}
|
||||||
|
|
||||||
|
List<VpcOfferingServiceMapVO> offeringProviders = _vpcOffSvcMapDao.listProvidersForServiceForVpcOffering(vpc.getVpcOfferingId(), Service.Firewall);
|
||||||
|
if (offeringProviders != null) {
|
||||||
|
for (VpcOfferingServiceMapVO offeringProvider : offeringProviders) {
|
||||||
|
Provider provider = Provider.getProvider(offeringProvider.getProvider());
|
||||||
|
if (provider != null) {
|
||||||
|
vpcProviders.add(provider);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return vpcProviders;
|
||||||
|
}
|
||||||
|
|
||||||
Map<Provider, Set<Service>> getProviderServicesMap(long networkId) {
|
Map<Provider, Set<Service>> getProviderServicesMap(long networkId) {
|
||||||
Map<Provider, Set<Service>> map = new HashMap<Provider, Set<Service>>();
|
Map<Provider, Set<Service>> map = new HashMap<Provider, Set<Service>>();
|
||||||
List<NetworkServiceMapVO> nsms = _ntwkSrvcDao.getServicesInNetwork(networkId);
|
List<NetworkServiceMapVO> nsms = _ntwkSrvcDao.getServicesInNetwork(networkId);
|
||||||
|
|||||||
@ -210,6 +210,10 @@ NetworkMigrationResponder, AggregatedCommandExecutor, RedundantResource, DnsServ
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected boolean canHandle(final Vpc vpc, final Service service) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean implement(final Network network, final NetworkOffering offering, final DeployDestination dest, final ReservationContext context)
|
public boolean implement(final Network network, final NetworkOffering offering, final DeployDestination dest, final ReservationContext context)
|
||||||
throws ResourceUnavailableException, ConcurrentOperationException, InsufficientCapacityException {
|
throws ResourceUnavailableException, ConcurrentOperationException, InsufficientCapacityException {
|
||||||
@ -279,7 +283,7 @@ NetworkMigrationResponder, AggregatedCommandExecutor, RedundantResource, DnsServ
|
|||||||
if (canHandle(network, Service.Firewall)) {
|
if (canHandle(network, Service.Firewall)) {
|
||||||
final List<DomainRouterVO> routers = getRouters(network);
|
final List<DomainRouterVO> routers = getRouters(network);
|
||||||
if (routers == null || routers.isEmpty()) {
|
if (routers == null || routers.isEmpty()) {
|
||||||
logger.debug("Virtual router element doesn't need to apply firewall rules on the backend; virtual router doesn't exist in the network {}", network);
|
logger.debug("Virtual router element doesn't need to apply firewall rules on the backend; virtual router doesn't exist in the network {}");
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -302,6 +306,7 @@ NetworkMigrationResponder, AggregatedCommandExecutor, RedundantResource, DnsServ
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean validateLBRule(final Network network, final LoadBalancingRule rule) {
|
public boolean validateLBRule(final Network network, final LoadBalancingRule rule) {
|
||||||
final List<LoadBalancingRule> rules = new ArrayList<LoadBalancingRule>();
|
final List<LoadBalancingRule> rules = new ArrayList<LoadBalancingRule>();
|
||||||
|
|||||||
@ -52,6 +52,7 @@ import com.cloud.network.router.VirtualRouter;
|
|||||||
import com.cloud.network.router.VirtualRouter.Role;
|
import com.cloud.network.router.VirtualRouter.Role;
|
||||||
import com.cloud.network.router.VpcNetworkHelperImpl;
|
import com.cloud.network.router.VpcNetworkHelperImpl;
|
||||||
import com.cloud.network.router.VpcVirtualNetworkApplianceManager;
|
import com.cloud.network.router.VpcVirtualNetworkApplianceManager;
|
||||||
|
import com.cloud.network.rules.FirewallRule;
|
||||||
import com.cloud.network.vpc.NetworkACLItem;
|
import com.cloud.network.vpc.NetworkACLItem;
|
||||||
import com.cloud.network.vpc.NetworkACLItemDao;
|
import com.cloud.network.vpc.NetworkACLItemDao;
|
||||||
import com.cloud.network.vpc.NetworkACLItemVO;
|
import com.cloud.network.vpc.NetworkACLItemVO;
|
||||||
@ -148,6 +149,49 @@ public class VpcVirtualRouterElement extends VirtualRouterElement implements Vpc
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected boolean canHandle(final Vpc vpc, final Service service) {
|
||||||
|
if (vpc == null) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!_networkMdl.isProviderEnabledInZone(vpc.getZoneId(), Network.Provider.VPCVirtualRouter.getName())) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (service != null && !_vpcMgr.isProviderSupportServiceInVpc(vpc.getId(), service, getProvider())) {
|
||||||
|
logger.trace("Element " + getProvider().getName() + " doesn't support service " + service.getName() + " in the vpc " + vpc);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean applyFWRulesInVPC(final Vpc vpc, final List<? extends FirewallRule> rules) throws ResourceUnavailableException {
|
||||||
|
boolean result = true;
|
||||||
|
if (canHandle(vpc, Service.Firewall)) {
|
||||||
|
final List<DomainRouterVO> routers = _routerDao.listByVpcId(vpc.getId());
|
||||||
|
if (CollectionUtils.isEmpty(routers)) {
|
||||||
|
logger.debug("Virtual router element doesn't need to apply firewall rules on the backend; virtual router doesn't exist in the vpc");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
Network network = null;
|
||||||
|
if (CollectionUtils.isNotEmpty(rules) && rules.get(0).getNetworkId() != null) {
|
||||||
|
network = _networkModel.getNetwork(rules.get(0).getNetworkId());
|
||||||
|
}
|
||||||
|
|
||||||
|
final DataCenterVO dcVO = _dcDao.findById(vpc.getZoneId());
|
||||||
|
final NetworkTopology networkTopology = networkTopologyContext.retrieveNetworkTopology(dcVO);
|
||||||
|
|
||||||
|
for (final DomainRouterVO domainRouterVO : routers) {
|
||||||
|
result = result && networkTopology.applyFirewallRulesInVPC(vpc, rules, domainRouterVO);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean implementVpc(final Vpc vpc, final DeployDestination dest, final ReservationContext context) throws ConcurrentOperationException, ResourceUnavailableException,
|
public boolean implementVpc(final Vpc vpc, final DeployDestination dest, final ReservationContext context) throws ConcurrentOperationException, ResourceUnavailableException,
|
||||||
InsufficientCapacityException {
|
InsufficientCapacityException {
|
||||||
@ -412,10 +456,6 @@ public class VpcVirtualRouterElement extends VirtualRouterElement implements Vpc
|
|||||||
vpnCapabilities.putAll(capabilities.get(Service.Vpn));
|
vpnCapabilities.putAll(capabilities.get(Service.Vpn));
|
||||||
vpnCapabilities.put(Capability.VpnTypes, "s2svpn");
|
vpnCapabilities.put(Capability.VpnTypes, "s2svpn");
|
||||||
capabilities.put(Service.Vpn, vpnCapabilities);
|
capabilities.put(Service.Vpn, vpnCapabilities);
|
||||||
|
|
||||||
// remove firewall capability
|
|
||||||
capabilities.remove(Service.Firewall);
|
|
||||||
|
|
||||||
// add network ACL capability
|
// add network ACL capability
|
||||||
final Map<Capability, String> networkACLCapabilities = new HashMap<Capability, String>();
|
final Map<Capability, String> networkACLCapabilities = new HashMap<Capability, String>();
|
||||||
networkACLCapabilities.put(Capability.SupportedProtocols, "tcp,udp,icmp");
|
networkACLCapabilities.put(Capability.SupportedProtocols, "tcp,udp,icmp");
|
||||||
|
|||||||
@ -203,25 +203,67 @@ public class FirewallManagerImpl extends ManagerBase implements FirewallService,
|
|||||||
if (sourceCidrs != null && !sourceCidrs.isEmpty())
|
if (sourceCidrs != null && !sourceCidrs.isEmpty())
|
||||||
Collections.replaceAll(sourceCidrs, "0.0.0.0/0", network.getCidr());
|
Collections.replaceAll(sourceCidrs, "0.0.0.0/0", network.getCidr());
|
||||||
|
|
||||||
return createFirewallRule(null, caller, rule.getXid(), rule.getSourcePortStart(), rule.getSourcePortEnd(), rule.getProtocol(), sourceCidrs, rule.getDestinationCidrList(),
|
return createFirewallRuleForNonVPC(null, caller, rule.getXid(), rule.getSourcePortStart(), rule.getSourcePortEnd(), rule.getProtocol(), sourceCidrs,
|
||||||
rule.getIcmpCode(), rule.getIcmpType(), null, rule.getType(), rule.getNetworkId(), rule.getTrafficType(), rule.isDisplay());
|
rule.getDestinationCidrList(), rule.getIcmpCode(), rule.getIcmpType(), null, rule.getType(), rule.getNetworkId(), rule.getTrafficType(), rule.isDisplay());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ActionEvent(eventType = EventTypes.EVENT_FIREWALL_OPEN, eventDescription = "creating firewall rule", create = true)
|
@ActionEvent(eventType = EventTypes.EVENT_FIREWALL_OPEN, eventDescription = "creating firewall rule", create = true)
|
||||||
public FirewallRule createIngressFirewallRule(FirewallRule rule) throws NetworkRuleConflictException {
|
public FirewallRule createIngressFirewallRule(FirewallRule rule) throws NetworkRuleConflictException {
|
||||||
Account caller = CallContext.current().getCallingAccount();
|
Account caller = CallContext.current().getCallingAccount();
|
||||||
Long sourceIpAddressId = rule.getSourceIpAddressId();
|
Long sourceIpAddressId = rule.getSourceIpAddressId();
|
||||||
|
IPAddressVO sourceIp = getSourceIpForIngressRule(sourceIpAddressId);
|
||||||
|
|
||||||
return createFirewallRule(sourceIpAddressId, caller, rule.getXid(), rule.getSourcePortStart(), rule.getSourcePortEnd(), rule.getProtocol(),
|
if (sourceIp.getVpcId() != null) {
|
||||||
rule.getSourceCidrList(), null, rule.getIcmpCode(), rule.getIcmpType(), null, rule.getType(), rule.getNetworkId(), rule.getTrafficType(), rule.isDisplay());
|
return createIngressFirewallRuleForVpcIp(rule, caller, sourceIp);
|
||||||
|
}
|
||||||
|
return createIngressFirewallRuleForIsolatedIp(rule, caller, sourceIp);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected IPAddressVO getSourceIpForIngressRule(Long sourceIpAddressId) {
|
||||||
|
if (sourceIpAddressId == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
IPAddressVO sourceIp = _ipAddressDao.findById(sourceIpAddressId);
|
||||||
|
if (sourceIp == null) {
|
||||||
|
throw new CloudRuntimeException("Unable to find IP address by id=" + sourceIpAddressId);
|
||||||
|
}
|
||||||
|
|
||||||
|
return sourceIp;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected FirewallRule createIngressFirewallRuleForIsolatedIp(FirewallRule rule, Account caller, IPAddressVO sourceIp)
|
||||||
|
throws NetworkRuleConflictException {
|
||||||
|
return createFirewallRuleForNonVPC(rule.getSourceIpAddressId(), caller, rule.getXid(), rule.getSourcePortStart(), rule.getSourcePortEnd(),
|
||||||
|
rule.getProtocol(), rule.getSourceCidrList(), null, rule.getIcmpCode(), rule.getIcmpType(), null, rule.getType(),
|
||||||
|
rule.getNetworkId(), rule.getTrafficType(), rule.isDisplay());
|
||||||
|
}
|
||||||
|
|
||||||
|
protected FirewallRule createIngressFirewallRuleForVpcIp(FirewallRule rule, Account caller, IPAddressVO sourceIp)
|
||||||
|
throws NetworkRuleConflictException {
|
||||||
|
Long vpcId = sourceIp != null ? sourceIp.getVpcId() : null;
|
||||||
|
return createFirewallRuleForVpc(rule.getSourceIpAddressId(), caller, rule.getXid(), rule.getSourcePortStart(), rule.getSourcePortEnd(),
|
||||||
|
rule.getProtocol(), rule.getSourceCidrList(), null, rule.getIcmpCode(), rule.getIcmpType(), null, rule.getType(),
|
||||||
|
vpcId, rule.getTrafficType(), rule.isDisplay());
|
||||||
}
|
}
|
||||||
|
|
||||||
//Destination CIDR capability is currently implemented for egress rules only. For others, the field is passed as null.
|
//Destination CIDR capability is currently implemented for egress rules only. For others, the field is passed as null.
|
||||||
@DB
|
@DB
|
||||||
protected FirewallRule createFirewallRule(final Long ipAddrId, Account caller, final String xId, final Integer portStart, final Integer portEnd, final String protocol,
|
protected FirewallRule createFirewallRule(final Long ipAddrId, Account caller, final String xId, final Integer portStart, final Integer portEnd, final String protocol,
|
||||||
final List<String> sourceCidrList, final List<String> destCidrList, final Integer icmpCode, final Integer icmpType, final Long relatedRuleId,
|
final List<String> sourceCidrList, final List<String> destCidrList, final Integer icmpCode, final Integer icmpType, final Long relatedRuleId,
|
||||||
final FirewallRule.FirewallRuleType type, final Long networkId, final FirewallRule.TrafficType trafficType, final Boolean forDisplay) throws NetworkRuleConflictException {
|
final FirewallRule.FirewallRuleType type, final Long networkId, final Long vpcId, final FirewallRule.TrafficType trafficType, final Boolean forDisplay) throws NetworkRuleConflictException {
|
||||||
|
if (vpcId != null) {
|
||||||
|
return createFirewallRuleForVpc(ipAddrId, caller, xId, portStart, portEnd, protocol, sourceCidrList, destCidrList, icmpCode, icmpType, relatedRuleId,
|
||||||
|
type, vpcId, trafficType, forDisplay);
|
||||||
|
}
|
||||||
|
return createFirewallRuleForNonVPC(ipAddrId, caller, xId, portStart, portEnd, protocol, sourceCidrList, destCidrList, icmpCode, icmpType, relatedRuleId,
|
||||||
|
type, networkId, trafficType, forDisplay);
|
||||||
|
}
|
||||||
|
|
||||||
|
@DB
|
||||||
|
protected FirewallRule createFirewallRuleForNonVPC(final Long ipAddrId, Account caller, final String xId, final Integer portStart, final Integer portEnd, final String protocol,
|
||||||
|
final List<String> sourceCidrList, final List<String> destCidrList, final Integer icmpCode, final Integer icmpType, final Long relatedRuleId,
|
||||||
|
final FirewallRule.FirewallRuleType type, final Long networkId, final FirewallRule.TrafficType trafficType, final Boolean forDisplay) throws NetworkRuleConflictException {
|
||||||
IPAddressVO ipAddress = null;
|
IPAddressVO ipAddress = null;
|
||||||
try {
|
try {
|
||||||
// Validate ip address
|
// Validate ip address
|
||||||
@ -288,6 +330,161 @@ public class FirewallManagerImpl extends ManagerBase implements FirewallService,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@DB
|
||||||
|
protected FirewallRule createFirewallRuleForVpc(final Long ipAddrId, Account caller, final String xId, final Integer portStart, final Integer portEnd, final String protocol,
|
||||||
|
final List<String> sourceCidrList, final List<String> destCidrList, final Integer icmpCode, final Integer icmpType,
|
||||||
|
final Long relatedRuleId, final FirewallRuleType type, final Long vpcId,
|
||||||
|
final FirewallRule.TrafficType trafficType, final Boolean forDisplay) throws NetworkRuleConflictException {
|
||||||
|
IPAddressVO ipAddress = null;
|
||||||
|
try {
|
||||||
|
Long resolvedVpcId = vpcId;
|
||||||
|
if (ipAddrId != null) {
|
||||||
|
ipAddress = _ipAddressDao.acquireInLockTable(ipAddrId);
|
||||||
|
if (ipAddress == null) {
|
||||||
|
throw new InvalidParameterValueException("Unable to create firewall rule; " + "couldn't locate IP address by id in the system");
|
||||||
|
}
|
||||||
|
resolvedVpcId = resolvedVpcId != null ? resolvedVpcId : ipAddress.getVpcId();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (resolvedVpcId == null) {
|
||||||
|
throw new InvalidParameterValueException("Unable to create VPC firewall rule; couldn't locate VPC id");
|
||||||
|
}
|
||||||
|
|
||||||
|
validateFirewallRuleForVpc(caller, ipAddress, portStart, portEnd, protocol, Purpose.Firewall, type, resolvedVpcId, trafficType);
|
||||||
|
|
||||||
|
if (!protocol.equalsIgnoreCase(NetUtils.ICMP_PROTO) && (icmpCode != null || icmpType != null)) {
|
||||||
|
throw new InvalidParameterValueException("Can specify icmpCode and icmpType for ICMP protocol only");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (protocol.equalsIgnoreCase(NetUtils.ICMP_PROTO) && (portStart != null || portEnd != null)) {
|
||||||
|
throw new InvalidParameterValueException("Can't specify start/end port when protocol is ICMP");
|
||||||
|
}
|
||||||
|
|
||||||
|
Long accountId = null;
|
||||||
|
Long domainId = null;
|
||||||
|
|
||||||
|
if (ipAddress != null) {
|
||||||
|
accountId = ipAddress.getAllocatedToAccountId();
|
||||||
|
domainId = ipAddress.getAllocatedInDomainId();
|
||||||
|
} else {
|
||||||
|
Vpc vpc = _vpcMgr.getActiveVpc(resolvedVpcId);
|
||||||
|
if (vpc == null) {
|
||||||
|
throw new InvalidParameterValueException("Unable to create VPC firewall rule; couldn't locate VPC by id=" + resolvedVpcId);
|
||||||
|
}
|
||||||
|
accountId = vpc.getAccountId();
|
||||||
|
domainId = vpc.getDomainId();
|
||||||
|
}
|
||||||
|
|
||||||
|
final Long accountIdFinal = accountId;
|
||||||
|
final Long domainIdFinal = domainId;
|
||||||
|
final Long resolvedNetworkIdFinal = null;
|
||||||
|
final Long resolvedVpcIdFinal = resolvedVpcId;
|
||||||
|
return Transaction.execute((TransactionCallbackWithException<FirewallRuleVO, NetworkRuleConflictException>) status -> {
|
||||||
|
FirewallRuleVO newRule = new FirewallRuleVO(xId, ipAddrId, portStart, portEnd, protocol.toLowerCase(), resolvedNetworkIdFinal, accountIdFinal, domainIdFinal, Purpose.Firewall,
|
||||||
|
sourceCidrList, destCidrList, icmpCode, icmpType, relatedRuleId, trafficType);
|
||||||
|
newRule.setVpcId(resolvedVpcIdFinal);
|
||||||
|
newRule.setType(type);
|
||||||
|
if (forDisplay != null) {
|
||||||
|
newRule.setDisplay(forDisplay);
|
||||||
|
}
|
||||||
|
newRule = _firewallDao.persist(newRule);
|
||||||
|
|
||||||
|
if (type == FirewallRuleType.User)
|
||||||
|
detectRulesConflict(newRule);
|
||||||
|
|
||||||
|
if (!_firewallDao.setStateToAdd(newRule)) {
|
||||||
|
throw new CloudRuntimeException("Unable to update the state to add for " + newRule);
|
||||||
|
}
|
||||||
|
CallContext.current().setEventDetails("Rule ID: " + newRule.getUuid());
|
||||||
|
CallContext.current().putContextParameter(FirewallRule.class, newRule.getId());
|
||||||
|
|
||||||
|
return newRule;
|
||||||
|
});
|
||||||
|
} finally {
|
||||||
|
if (ipAddrId != null) {
|
||||||
|
_ipAddressDao.releaseFromLockTable(ipAddrId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void validateFirewallRuleForVpc(Account caller, IPAddressVO ipAddress, Integer portStart, Integer portEnd, String proto, Purpose purpose,
|
||||||
|
FirewallRuleType type, Long vpcId, FirewallRule.TrafficType trafficType) {
|
||||||
|
if (portStart != null && !NetUtils.isValidPort(portStart)) {
|
||||||
|
throw new InvalidParameterValueException("publicPort is an invalid value: " + portStart);
|
||||||
|
}
|
||||||
|
if (portEnd != null && !NetUtils.isValidPort(portEnd)) {
|
||||||
|
throw new InvalidParameterValueException("Public port range is an invalid value: " + portEnd);
|
||||||
|
}
|
||||||
|
if (portStart != null && portEnd != null && portStart > portEnd) {
|
||||||
|
throw new InvalidParameterValueException("Start port can't be bigger than end port");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ipAddress == null && type == FirewallRuleType.System) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (vpcId == null) {
|
||||||
|
throw new InvalidParameterValueException("Unable to retrieve VPC id to validate the rule");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ipAddress != null) {
|
||||||
|
_accountMgr.checkAccess(caller, null, true, ipAddress);
|
||||||
|
}
|
||||||
|
|
||||||
|
Vpc vpc = _vpcMgr.getActiveVpc(vpcId);
|
||||||
|
if (vpc == null) {
|
||||||
|
throw new InvalidParameterValueException("Unable to retrieve VPC to validate the rule by id=" + vpcId);
|
||||||
|
}
|
||||||
|
|
||||||
|
Map<Network.Capability, String> caps = null;
|
||||||
|
if (purpose == Purpose.Firewall) {
|
||||||
|
caps = getFirewallServiceCapabilitiesForVpc(vpcId);
|
||||||
|
if (caps == null) {
|
||||||
|
throw new InvalidParameterValueException("Firewall service is not supported in VPC " + vpc);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (caps != null) {
|
||||||
|
String supportedTrafficTypes = null;
|
||||||
|
if (purpose == FirewallRule.Purpose.Firewall) {
|
||||||
|
supportedTrafficTypes = caps.get(Capability.SupportedTrafficDirection).toLowerCase();
|
||||||
|
}
|
||||||
|
|
||||||
|
String supportedProtocols;
|
||||||
|
if (purpose == FirewallRule.Purpose.Firewall && trafficType == FirewallRule.TrafficType.Egress) {
|
||||||
|
supportedProtocols = caps.get(Capability.SupportedEgressProtocols).toLowerCase();
|
||||||
|
} else {
|
||||||
|
supportedProtocols = caps.get(Capability.SupportedProtocols).toLowerCase();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!supportedProtocols.contains(proto.toLowerCase())) {
|
||||||
|
throw new InvalidParameterValueException("Protocol " + proto + " is not supported in VPC " + vpcId);
|
||||||
|
} else if (proto.equalsIgnoreCase(NetUtils.ICMP_PROTO) && purpose != Purpose.Firewall) {
|
||||||
|
throw new InvalidParameterValueException("Protocol " + proto + " is currently supported only for rules with purpose " + Purpose.Firewall);
|
||||||
|
} else if (purpose == Purpose.Firewall && !supportedTrafficTypes.contains(trafficType.toString().toLowerCase())) {
|
||||||
|
throw new InvalidParameterValueException(String.format("Traffic Type %s is currently supported by Firewall in VPC %s", trafficType, vpc.getUuid()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected Map<Network.Capability, String> getFirewallServiceCapabilitiesForVpc(Long vpcId) {
|
||||||
|
for (FirewallServiceProvider fwElement : _firewallElements) {
|
||||||
|
Network.Provider provider = fwElement.getProvider();
|
||||||
|
if (_vpcMgr.isProviderSupportServiceInVpc(vpcId, Service.Firewall, provider)) {
|
||||||
|
Map<Service, Map<Capability, String>> capabilities = fwElement.getCapabilities();
|
||||||
|
if (capabilities != null && capabilities.get(Service.Firewall) != null) {
|
||||||
|
return capabilities.get(Service.Firewall);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected Long resolveIsolatedFirewallRuleNetworkId(IPAddressVO ipAddress, Long networkId) {
|
||||||
|
_networkModel.checkIpForService(ipAddress, Service.Firewall, networkId);
|
||||||
|
return ipAddress.getAssociatedWithNetworkId();
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Pair<List<? extends FirewallRule>, Integer> listFirewallRules(IListFirewallRulesCmd cmd) {
|
public Pair<List<? extends FirewallRule>, Integer> listFirewallRules(IListFirewallRulesCmd cmd) {
|
||||||
Long ipId = cmd.getIpAddressId();
|
Long ipId = cmd.getIpAddressId();
|
||||||
@ -404,9 +601,16 @@ public class FirewallManagerImpl extends ManagerBase implements FirewallService,
|
|||||||
assert (rules.size() >= 1);
|
assert (rules.size() >= 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
NetworkVO newRuleNetwork = getNewRuleNetwork(newRule);
|
Long newRuleVpcId = newRule.getVpcId();
|
||||||
boolean newRuleIsOnVpcNetwork = newRuleNetwork.getVpcId() != null;
|
boolean newRuleIsVpc = newRuleVpcId != null;
|
||||||
boolean vpcConserveModeEnabled = _vpcMgr.isNetworkOnVpcEnabledConserveMode(newRuleNetwork);
|
NetworkVO newRuleNetwork = null;
|
||||||
|
boolean newRuleIsOnVpcNetwork = false;
|
||||||
|
boolean vpcConserveModeEnabled = false;
|
||||||
|
if (!newRuleIsVpc) {
|
||||||
|
newRuleNetwork = getNewRuleNetwork(newRule);
|
||||||
|
newRuleIsOnVpcNetwork = newRuleNetwork.getVpcId() != null;
|
||||||
|
vpcConserveModeEnabled = newRuleIsOnVpcNetwork && _vpcMgr.isNetworkOnVpcEnabledConserveMode(newRuleNetwork);
|
||||||
|
}
|
||||||
|
|
||||||
for (FirewallRuleVO rule : rules) {
|
for (FirewallRuleVO rule : rules) {
|
||||||
if (rule.getId() == newRule.getId()) {
|
if (rule.getId() == newRule.getId()) {
|
||||||
@ -457,8 +661,8 @@ public class FirewallManagerImpl extends ManagerBase implements FirewallService,
|
|||||||
|
|
||||||
// Checking if the rule applied is to the same network that is passed in the rule.
|
// Checking if the rule applied is to the same network that is passed in the rule.
|
||||||
// (except for VPCs with conserve mode = true)
|
// (except for VPCs with conserve mode = true)
|
||||||
if ((!newRuleIsOnVpcNetwork || !vpcConserveModeEnabled)
|
if (!newRuleIsVpc && (!newRuleIsOnVpcNetwork || !vpcConserveModeEnabled)
|
||||||
&& rule.getNetworkId() != newRule.getNetworkId() && rule.getState() != State.Revoke) {
|
&& !Objects.equals(rule.getNetworkId(), newRule.getNetworkId()) && rule.getState() != State.Revoke) {
|
||||||
String errMsg = String.format("New rule is for a different network than what's specified in rule %s", rule.getXid());
|
String errMsg = String.format("New rule is for a different network than what's specified in rule %s", rule.getXid());
|
||||||
if (newRuleIsOnVpcNetwork) {
|
if (newRuleIsOnVpcNetwork) {
|
||||||
Vpc vpc = _vpcMgr.getActiveVpc(newRuleNetwork.getVpcId());
|
Vpc vpc = _vpcMgr.getActiveVpc(newRuleNetwork.getVpcId());
|
||||||
@ -580,11 +784,9 @@ public class FirewallManagerImpl extends ManagerBase implements FirewallService,
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (ipAddress != null) {
|
if (ipAddress != null) {
|
||||||
if (ipAddress.getAssociatedWithNetworkId() == null) {
|
networkId = isVpcIpAddress(ipAddress)
|
||||||
throw new InvalidParameterValueException("Unable to create firewall rule ; ip with specified id is not associated with any network");
|
? validateFirewallRuleForVpcIp(ipAddress, networkId)
|
||||||
} else {
|
: validateFirewallRuleForIsolatedIp(ipAddress);
|
||||||
networkId = ipAddress.getAssociatedWithNetworkId();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Validate ip address
|
// Validate ip address
|
||||||
_accountMgr.checkAccess(caller, null, true, ipAddress);
|
_accountMgr.checkAccess(caller, null, true, ipAddress);
|
||||||
@ -615,7 +817,7 @@ public class FirewallManagerImpl extends ManagerBase implements FirewallService,
|
|||||||
if (routedIpv4Manager.isVirtualRouterGateway(network)) {
|
if (routedIpv4Manager.isVirtualRouterGateway(network)) {
|
||||||
throw new CloudRuntimeException("Unable to create routing firewall rule. Please use routing firewall API instead.");
|
throw new CloudRuntimeException("Unable to create routing firewall rule. Please use routing firewall API instead.");
|
||||||
}
|
}
|
||||||
caps = _networkModel.getNetworkServiceCapabilities(network.getId(), Service.Firewall);
|
caps = getFirewallServiceCapabilities(network);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (caps != null) {
|
if (caps != null) {
|
||||||
@ -655,6 +857,41 @@ public class FirewallManagerImpl extends ManagerBase implements FirewallService,
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected boolean isVpcIpAddress(IPAddressVO ipAddress) {
|
||||||
|
return ipAddress.getVpcId() != null;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected Long validateFirewallRuleForIsolatedIp(IPAddressVO ipAddress) {
|
||||||
|
if (ipAddress.getAssociatedWithNetworkId() == null) {
|
||||||
|
throw new InvalidParameterValueException("Unable to create firewall rule ; ip with specified id is not associated with any network");
|
||||||
|
}
|
||||||
|
return ipAddress.getAssociatedWithNetworkId();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected Long validateFirewallRuleForVpcIp(IPAddressVO ipAddress, Long networkId) {
|
||||||
|
if (networkId == null) {
|
||||||
|
throw new InvalidParameterValueException("Unable to retrieve network id to validate the rule");
|
||||||
|
}
|
||||||
|
return networkId;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected Map<Network.Capability, String> getFirewallServiceCapabilities(Network network) {
|
||||||
|
if (network.getVpcId() == null) {
|
||||||
|
return _networkModel.getNetworkServiceCapabilities(network.getId(), Service.Firewall);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (FirewallServiceProvider fwElement : _firewallElements) {
|
||||||
|
Network.Provider provider = fwElement.getProvider();
|
||||||
|
if (_vpcMgr.isProviderSupportServiceInVpc(network.getVpcId(), Service.Firewall, provider)) {
|
||||||
|
Map<Service, Map<Capability, String>> capabilities = fwElement.getCapabilities();
|
||||||
|
if (capabilities != null && capabilities.get(Service.Firewall) != null) {
|
||||||
|
return capabilities.get(Service.Firewall);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return _networkModel.getNetworkServiceCapabilities(network.getId(), Service.Firewall);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean applyRules(List<? extends FirewallRule> rules, boolean continueOnError, boolean updateRulesInDB) throws ResourceUnavailableException {
|
public boolean applyRules(List<? extends FirewallRule> rules, boolean continueOnError, boolean updateRulesInDB) throws ResourceUnavailableException {
|
||||||
boolean success = true;
|
boolean success = true;
|
||||||
@ -683,7 +920,7 @@ public class FirewallManagerImpl extends ManagerBase implements FirewallService,
|
|||||||
success = false;
|
success = false;
|
||||||
} else {
|
} else {
|
||||||
removeRule(rule);
|
removeRule(rule);
|
||||||
if (rule.getSourceIpAddressId() != null) {
|
if (rule.getSourceIpAddressId() != null && rule.getVpcId() == null) {
|
||||||
//if the rule is the last one for the ip address assigned to VPC, unassign it from the network
|
//if the rule is the last one for the ip address assigned to VPC, unassign it from the network
|
||||||
_vpcMgr.unassignIPFromVpcNetwork(rule.getSourceIpAddressId(), rule.getNetworkId());
|
_vpcMgr.unassignIPFromVpcNetwork(rule.getSourceIpAddressId(), rule.getNetworkId());
|
||||||
}
|
}
|
||||||
@ -701,7 +938,7 @@ public class FirewallManagerImpl extends ManagerBase implements FirewallService,
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean applyRules(Network network, Purpose purpose, List<? extends FirewallRule> rules) throws ResourceUnavailableException {
|
public boolean applyRules(Network network, Vpc vpc, Purpose purpose, List<? extends FirewallRule> rules) throws ResourceUnavailableException {
|
||||||
boolean handled = false;
|
boolean handled = false;
|
||||||
switch (purpose) {
|
switch (purpose) {
|
||||||
/* StaticNatRule would be applied by Firewall provider, since the incompatible of two object */
|
/* StaticNatRule would be applied by Firewall provider, since the incompatible of two object */
|
||||||
@ -710,11 +947,26 @@ public class FirewallManagerImpl extends ManagerBase implements FirewallService,
|
|||||||
case Ipv6Firewall:
|
case Ipv6Firewall:
|
||||||
for (FirewallServiceProvider fwElement : _firewallElements) {
|
for (FirewallServiceProvider fwElement : _firewallElements) {
|
||||||
Network.Provider provider = fwElement.getProvider();
|
Network.Provider provider = fwElement.getProvider();
|
||||||
boolean isFwProvider = _networkModel.isProviderSupportServiceInNetwork(network.getId(), Service.Firewall, provider);
|
boolean isFwProvider;
|
||||||
|
Long effectiveVpcId = null;
|
||||||
|
if (vpc != null) {
|
||||||
|
effectiveVpcId = vpc.getId();
|
||||||
|
} else if (network != null) {
|
||||||
|
effectiveVpcId = network.getVpcId();
|
||||||
|
}
|
||||||
|
if (effectiveVpcId != null) {
|
||||||
|
isFwProvider = _vpcMgr.isProviderSupportServiceInVpc(effectiveVpcId, Service.Firewall, provider);
|
||||||
|
} else {
|
||||||
|
isFwProvider = _networkModel.isProviderSupportServiceInNetwork(network.getId(), Service.Firewall, provider);
|
||||||
|
}
|
||||||
if (!isFwProvider) {
|
if (!isFwProvider) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
handled = fwElement.applyFWRules(network, rules);
|
if (vpc != null) {
|
||||||
|
handled = fwElement.applyFWRulesInVPC(vpc, rules);
|
||||||
|
} else {
|
||||||
|
handled = fwElement.applyFWRules(network, rules);
|
||||||
|
}
|
||||||
if (handled)
|
if (handled)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -771,6 +1023,11 @@ public class FirewallManagerImpl extends ManagerBase implements FirewallService,
|
|||||||
return handled;
|
return handled;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean applyRules(Network network, Purpose purpose, List<? extends FirewallRule> rules) throws ResourceUnavailableException {
|
||||||
|
return applyRules(network, null, purpose, rules);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void removeRule(FirewallRule rule) {
|
public void removeRule(FirewallRule rule) {
|
||||||
|
|
||||||
@ -817,8 +1074,10 @@ public class FirewallManagerImpl extends ManagerBase implements FirewallService,
|
|||||||
|
|
||||||
for (FirewallRuleVO rule : rules) {
|
for (FirewallRuleVO rule : rules) {
|
||||||
// validate rule - for NSX
|
// validate rule - for NSX
|
||||||
long networkId = rule.getNetworkId();
|
Long networkId = rule.getNetworkId();
|
||||||
validateNsxConstraints(networkId, rule);
|
if (networkId != null) {
|
||||||
|
validateNsxConstraints(networkId, rule);
|
||||||
|
}
|
||||||
// load cidrs if any
|
// load cidrs if any
|
||||||
rule.setSourceCidrList(_firewallCidrsDao.getSourceCidrs(rule.getId()));
|
rule.setSourceCidrList(_firewallCidrsDao.getSourceCidrs(rule.getId()));
|
||||||
rule.setDestinationCidrsList(_firewallDcidrsDao.getDestCidrs(rule.getId()));
|
rule.setDestinationCidrsList(_firewallDcidrsDao.getDestCidrs(rule.getId()));
|
||||||
@ -1078,7 +1337,7 @@ public class FirewallManagerImpl extends ManagerBase implements FirewallService,
|
|||||||
List<String> oneCidr = new ArrayList<String>();
|
List<String> oneCidr = new ArrayList<String>();
|
||||||
oneCidr.add(NetUtils.ALL_IP4_CIDRS);
|
oneCidr.add(NetUtils.ALL_IP4_CIDRS);
|
||||||
return createFirewallRule(ipAddrId, caller, null, startPort, endPort, protocol, oneCidr, null, icmpCode, icmpType, relatedRuleId, FirewallRule.FirewallRuleType.User,
|
return createFirewallRule(ipAddrId, caller, null, startPort, endPort, protocol, oneCidr, null, icmpCode, icmpType, relatedRuleId, FirewallRule.FirewallRuleType.User,
|
||||||
networkId, FirewallRule.TrafficType.Ingress, true);
|
networkId, null, FirewallRule.TrafficType.Ingress, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -1193,7 +1452,7 @@ public class FirewallManagerImpl extends ManagerBase implements FirewallService,
|
|||||||
_firewallDao.loadSourceCidrs(rule);
|
_firewallDao.loadSourceCidrs(rule);
|
||||||
}
|
}
|
||||||
createFirewallRule(ip.getId(), acct, rule.getXid(), rule.getSourcePortStart(), rule.getSourcePortEnd(), rule.getProtocol(), rule.getSourceCidrList(),null,
|
createFirewallRule(ip.getId(), acct, rule.getXid(), rule.getSourcePortStart(), rule.getSourcePortEnd(), rule.getProtocol(), rule.getSourceCidrList(),null,
|
||||||
rule.getIcmpCode(), rule.getIcmpType(), rule.getRelated(), FirewallRuleType.System, rule.getNetworkId(), rule.getTrafficType(), true);
|
rule.getIcmpCode(), rule.getIcmpType(), rule.getRelated(), FirewallRuleType.System, rule.getNetworkId(), rule.getVpcId(), rule.getTrafficType(), true);
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
logger.debug("Failed to add system wide firewall rule, due to:" + e.toString());
|
logger.debug("Failed to add system wide firewall rule, due to:" + e.toString());
|
||||||
}
|
}
|
||||||
|
|||||||
@ -463,7 +463,8 @@ public class CommandSetupHelper {
|
|||||||
cmds.addCommand(cmd);
|
cmds.addCommand(cmd);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void createApplyFirewallRulesCommands(final List<? extends FirewallRule> rules, final VirtualRouter router, final Commands cmds, final long guestNetworkId) {
|
public void createApplyFirewallRulesCommands(final List<? extends FirewallRule> rules, final VirtualRouter router, final Commands cmds,
|
||||||
|
final Long guestNetworkId, final Long vpcId) {
|
||||||
final List<FirewallRuleTO> rulesTO = new ArrayList<>();
|
final List<FirewallRuleTO> rulesTO = new ArrayList<>();
|
||||||
String systemRule = null;
|
String systemRule = null;
|
||||||
Boolean defaultEgressPolicy = false;
|
Boolean defaultEgressPolicy = false;
|
||||||
@ -485,6 +486,10 @@ public class CommandSetupHelper {
|
|||||||
final FirewallRuleTO ruleTO = new FirewallRuleTO(rule, null, srcIp, Purpose.Firewall, traffictype);
|
final FirewallRuleTO ruleTO = new FirewallRuleTO(rule, null, srcIp, Purpose.Firewall, traffictype);
|
||||||
rulesTO.add(ruleTO);
|
rulesTO.add(ruleTO);
|
||||||
} else if (rule.getTrafficType() == FirewallRule.TrafficType.Egress) {
|
} else if (rule.getTrafficType() == FirewallRule.TrafficType.Egress) {
|
||||||
|
if (guestNetworkId == null) {
|
||||||
|
logger.warn("Skipping egress firewall rule {} as guestNetworkId is null", rule.getUuid());
|
||||||
|
continue;
|
||||||
|
}
|
||||||
final NetworkVO network = _networkDao.findById(guestNetworkId);
|
final NetworkVO network = _networkDao.findById(guestNetworkId);
|
||||||
final NetworkOfferingVO offering = _networkOfferingDao.findById(network.getNetworkOfferingId());
|
final NetworkOfferingVO offering = _networkOfferingDao.findById(network.getNetworkOfferingId());
|
||||||
defaultEgressPolicy = offering.isEgressDefaultPolicy();
|
defaultEgressPolicy = offering.isEgressDefaultPolicy();
|
||||||
@ -495,9 +500,14 @@ public class CommandSetupHelper {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
final SetFirewallRulesCommand cmd = new SetFirewallRulesCommand(rulesTO);
|
final SetFirewallRulesCommand cmd = new SetFirewallRulesCommand(rulesTO, vpcId);
|
||||||
cmd.setAccessDetail(NetworkElementCommand.ROUTER_IP, _routerControlHelper.getRouterControlIp(router.getId()));
|
cmd.setAccessDetail(NetworkElementCommand.ROUTER_IP, _routerControlHelper.getRouterControlIp(router.getId()));
|
||||||
cmd.setAccessDetail(NetworkElementCommand.ROUTER_GUEST_IP, _routerControlHelper.getRouterIpInNetwork(guestNetworkId, router.getId()));
|
if (guestNetworkId != null) {
|
||||||
|
cmd.setAccessDetail(NetworkElementCommand.ROUTER_GUEST_IP, _routerControlHelper.getRouterIpInNetwork(guestNetworkId, router.getId()));
|
||||||
|
}
|
||||||
|
if (vpcId != null) {
|
||||||
|
cmd.setAccessDetail(NetworkElementCommand.VPC_ID, String.valueOf(vpcId));
|
||||||
|
}
|
||||||
cmd.setAccessDetail(NetworkElementCommand.ROUTER_NAME, router.getInstanceName());
|
cmd.setAccessDetail(NetworkElementCommand.ROUTER_NAME, router.getInstanceName());
|
||||||
final DataCenterVO dcVo = _dcDao.findById(router.getDataCenterId());
|
final DataCenterVO dcVo = _dcDao.findById(router.getDataCenterId());
|
||||||
cmd.setAccessDetail(NetworkElementCommand.ZONE_NETWORK_TYPE, dcVo.getNetworkType().toString());
|
cmd.setAccessDetail(NetworkElementCommand.ZONE_NETWORK_TYPE, dcVo.getNetworkType().toString());
|
||||||
@ -510,6 +520,10 @@ public class CommandSetupHelper {
|
|||||||
cmds.addCommand(cmd);
|
cmds.addCommand(cmd);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void createApplyFirewallRulesCommands(final List<? extends FirewallRule> rules, final VirtualRouter router, final Commands cmds, final long guestNetworkId) {
|
||||||
|
createApplyFirewallRulesCommands(rules, router, cmds, guestNetworkId, null);
|
||||||
|
}
|
||||||
|
|
||||||
public void createApplyIpv6FirewallRulesCommands(final List<? extends FirewallRule> rules, final VirtualRouter router, final Commands cmds, final long guestNetworkId) {
|
public void createApplyIpv6FirewallRulesCommands(final List<? extends FirewallRule> rules, final VirtualRouter router, final Commands cmds, final long guestNetworkId) {
|
||||||
final List<FirewallRuleTO> rulesTO = new ArrayList<>();
|
final List<FirewallRuleTO> rulesTO = new ArrayList<>();
|
||||||
String systemRule = null;
|
String systemRule = null;
|
||||||
@ -551,7 +565,8 @@ public class CommandSetupHelper {
|
|||||||
cmds.addCommand(cmd);
|
cmds.addCommand(cmd);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void createFirewallRulesCommands(final List<? extends FirewallRule> rules, final VirtualRouter router, final Commands cmds, final long guestNetworkId) {
|
public void createFirewallRulesCommands(final List<? extends FirewallRule> rules, final VirtualRouter router, final Commands cmds, final Long guestNetworkId,
|
||||||
|
final Long vpcId) {
|
||||||
final List<FirewallRuleTO> rulesTO = new ArrayList<>();
|
final List<FirewallRuleTO> rulesTO = new ArrayList<>();
|
||||||
String systemRule = null;
|
String systemRule = null;
|
||||||
Boolean defaultEgressPolicy = false;
|
Boolean defaultEgressPolicy = false;
|
||||||
@ -573,6 +588,10 @@ public class CommandSetupHelper {
|
|||||||
final FirewallRuleTO ruleTO = new FirewallRuleTO(rule, null, srcIp, Purpose.Firewall, traffictype);
|
final FirewallRuleTO ruleTO = new FirewallRuleTO(rule, null, srcIp, Purpose.Firewall, traffictype);
|
||||||
rulesTO.add(ruleTO);
|
rulesTO.add(ruleTO);
|
||||||
} else if (rule.getTrafficType() == FirewallRule.TrafficType.Egress) {
|
} else if (rule.getTrafficType() == FirewallRule.TrafficType.Egress) {
|
||||||
|
if (guestNetworkId == null) {
|
||||||
|
logger.warn("Skipping egress firewall rule {} as guestNetworkId is null", rule.getUuid());
|
||||||
|
continue;
|
||||||
|
}
|
||||||
final NetworkVO network = _networkDao.findById(guestNetworkId);
|
final NetworkVO network = _networkDao.findById(guestNetworkId);
|
||||||
final NetworkOfferingVO offering = _networkOfferingDao.findById(network.getNetworkOfferingId());
|
final NetworkOfferingVO offering = _networkOfferingDao.findById(network.getNetworkOfferingId());
|
||||||
defaultEgressPolicy = offering.isEgressDefaultPolicy();
|
defaultEgressPolicy = offering.isEgressDefaultPolicy();
|
||||||
@ -583,9 +602,14 @@ public class CommandSetupHelper {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
final SetFirewallRulesCommand cmd = new SetFirewallRulesCommand(rulesTO);
|
final SetFirewallRulesCommand cmd = new SetFirewallRulesCommand(rulesTO, vpcId);
|
||||||
cmd.setAccessDetail(NetworkElementCommand.ROUTER_IP, _routerControlHelper.getRouterControlIp(router.getId()));
|
cmd.setAccessDetail(NetworkElementCommand.ROUTER_IP, _routerControlHelper.getRouterControlIp(router.getId()));
|
||||||
cmd.setAccessDetail(NetworkElementCommand.ROUTER_GUEST_IP, _routerControlHelper.getRouterIpInNetwork(guestNetworkId, router.getId()));
|
if (guestNetworkId != null) {
|
||||||
|
cmd.setAccessDetail(NetworkElementCommand.ROUTER_GUEST_IP, _routerControlHelper.getRouterIpInNetwork(guestNetworkId, router.getId()));
|
||||||
|
}
|
||||||
|
if (vpcId != null) {
|
||||||
|
cmd.setAccessDetail(NetworkElementCommand.VPC_ID, String.valueOf(vpcId));
|
||||||
|
}
|
||||||
cmd.setAccessDetail(NetworkElementCommand.ROUTER_NAME, router.getInstanceName());
|
cmd.setAccessDetail(NetworkElementCommand.ROUTER_NAME, router.getInstanceName());
|
||||||
final DataCenterVO dcVo = _dcDao.findById(router.getDataCenterId());
|
final DataCenterVO dcVo = _dcDao.findById(router.getDataCenterId());
|
||||||
cmd.setAccessDetail(NetworkElementCommand.ZONE_NETWORK_TYPE, dcVo.getNetworkType().toString());
|
cmd.setAccessDetail(NetworkElementCommand.ZONE_NETWORK_TYPE, dcVo.getNetworkType().toString());
|
||||||
@ -598,6 +622,10 @@ public class CommandSetupHelper {
|
|||||||
cmds.addCommand(cmd);
|
cmds.addCommand(cmd);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void createFirewallRulesCommands(final List<? extends FirewallRule> rules, final VirtualRouter router, final Commands cmds, final Long guestNetworkId) {
|
||||||
|
createFirewallRulesCommands(rules, router, cmds, guestNetworkId, router.getVpcId());
|
||||||
|
}
|
||||||
|
|
||||||
public void createIpv6FirewallRulesCommands(final List<? extends FirewallRule> rules, final VirtualRouter router, final Commands cmds, final long guestNetworkId) {
|
public void createIpv6FirewallRulesCommands(final List<? extends FirewallRule> rules, final VirtualRouter router, final Commands cmds, final long guestNetworkId) {
|
||||||
final List<FirewallRuleTO> rulesTO = new ArrayList<>();
|
final List<FirewallRuleTO> rulesTO = new ArrayList<>();
|
||||||
String systemRule = null;
|
String systemRule = null;
|
||||||
|
|||||||
@ -2018,6 +2018,8 @@ Configurable, StateListener<VirtualMachine.State, VirtualMachine.Event, VirtualM
|
|||||||
} else {
|
} else {
|
||||||
buf.append(" has_public_network=false");
|
buf.append(" has_public_network=false");
|
||||||
}
|
}
|
||||||
|
boolean isVpcFirewallEnabled = vpcManager.isProviderSupportServiceInVpc(vpc.getId(), Service.Firewall, Provider.VPCVirtualRouter);
|
||||||
|
buf.append(" vpc_firewall_enabled=").append(isVpcFirewallEnabled);
|
||||||
} else if (!publicNetwork) {
|
} else if (!publicNetwork) {
|
||||||
type = "dhcpsrvr";
|
type = "dhcpsrvr";
|
||||||
} else {
|
} else {
|
||||||
@ -2497,7 +2499,7 @@ Configurable, StateListener<VirtualMachine.State, VirtualMachine.Event, VirtualM
|
|||||||
// Re-apply firewall Egress rules
|
// Re-apply firewall Egress rules
|
||||||
logger.debug("Found " + firewallRulesEgress.size() + " firewall Egress rule(s) to apply as a part of domR " + router + " start.");
|
logger.debug("Found " + firewallRulesEgress.size() + " firewall Egress rule(s) to apply as a part of domR " + router + " start.");
|
||||||
if (!firewallRulesEgress.isEmpty()) {
|
if (!firewallRulesEgress.isEmpty()) {
|
||||||
_commandSetupHelper.createFirewallRulesCommands(firewallRulesEgress, router, cmds, guestNetworkId);
|
_commandSetupHelper.createFirewallRulesCommands(firewallRulesEgress, router, cmds, guestNetworkId, router.getVpcId());
|
||||||
}
|
}
|
||||||
|
|
||||||
logger.debug(String.format("Found %d Ipv6 firewall rule(s) to apply as a part of domR %s start.", ipv6firewallRules.size(), router));
|
logger.debug(String.format("Found %d Ipv6 firewall rule(s) to apply as a part of domR %s start.", ipv6firewallRules.size(), router));
|
||||||
@ -2572,7 +2574,7 @@ Configurable, StateListener<VirtualMachine.State, VirtualMachine.Event, VirtualM
|
|||||||
// Re-apply firewall Ingress rules
|
// Re-apply firewall Ingress rules
|
||||||
logger.debug("Found " + firewallRulesIngress.size() + " firewall Ingress rule(s) to apply as a part of domR " + router + " start.");
|
logger.debug("Found " + firewallRulesIngress.size() + " firewall Ingress rule(s) to apply as a part of domR " + router + " start.");
|
||||||
if (!firewallRulesIngress.isEmpty()) {
|
if (!firewallRulesIngress.isEmpty()) {
|
||||||
_commandSetupHelper.createFirewallRulesCommands(firewallRulesIngress, router, cmds, guestNetworkId);
|
_commandSetupHelper.createFirewallRulesCommands(firewallRulesIngress, router, cmds, guestNetworkId, router.getVpcId());
|
||||||
}
|
}
|
||||||
|
|
||||||
// Re-apply port forwarding rules
|
// Re-apply port forwarding rules
|
||||||
|
|||||||
@ -72,6 +72,7 @@ import com.cloud.network.dao.LoadBalancerDao;
|
|||||||
import com.cloud.network.dao.LoadBalancerVO;
|
import com.cloud.network.dao.LoadBalancerVO;
|
||||||
import com.cloud.network.dao.MonitoringServiceVO;
|
import com.cloud.network.dao.MonitoringServiceVO;
|
||||||
import com.cloud.network.dao.NetworkVO;
|
import com.cloud.network.dao.NetworkVO;
|
||||||
|
import com.cloud.network.rules.FirewallRule;
|
||||||
import com.cloud.network.dao.RemoteAccessVpnVO;
|
import com.cloud.network.dao.RemoteAccessVpnVO;
|
||||||
import com.cloud.network.dao.Site2SiteVpnConnectionVO;
|
import com.cloud.network.dao.Site2SiteVpnConnectionVO;
|
||||||
import com.cloud.network.lb.LoadBalancingRule;
|
import com.cloud.network.lb.LoadBalancingRule;
|
||||||
@ -567,6 +568,10 @@ public class VpcVirtualNetworkApplianceManagerImpl extends VirtualNetworkApplian
|
|||||||
finalizeMonitorService(cmds, profile, domainRouterVO, provider, publicNics.get(0).second().getId(), true, routerHealthCheckConfig);
|
finalizeMonitorService(cmds, profile, domainRouterVO, provider, publicNics.get(0).second().getId(), true, routerHealthCheckConfig);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (reprogramGuestNtwks) {
|
||||||
|
reapplyVpcFirewallIngressRules(cmds, domainRouterVO, provider);
|
||||||
|
}
|
||||||
|
|
||||||
for (final Pair<Nic, Network> nicNtwk : guestNics) {
|
for (final Pair<Nic, Network> nicNtwk : guestNics) {
|
||||||
final Nic guestNic = nicNtwk.first();
|
final Nic guestNic = nicNtwk.first();
|
||||||
final long guestNetworkId = guestNic.getNetworkId();
|
final long guestNetworkId = guestNic.getNetworkId();
|
||||||
@ -638,6 +643,26 @@ public class VpcVirtualNetworkApplianceManagerImpl extends VirtualNetworkApplian
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void reapplyVpcFirewallIngressRules(final Commands cmds, final DomainRouterVO domainRouterVO, final Provider provider) {
|
||||||
|
final Long vpcId = domainRouterVO.getVpcId();
|
||||||
|
if (vpcId == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!_vpcMgr.isProviderSupportServiceInVpc(vpcId, Service.Firewall, provider)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
final List<FirewallRule> firewallRulesIngress = new ArrayList<>(
|
||||||
|
_rulesDao.listByVpcPurposeTrafficType(vpcId, FirewallRule.Purpose.Firewall, FirewallRule.TrafficType.Ingress));
|
||||||
|
if (firewallRulesIngress.isEmpty()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
logger.debug("Found {} VPC firewall ingress rule(s) to apply as a part of domR {} start for VPC {}", firewallRulesIngress.size(), domainRouterVO, vpcId);
|
||||||
|
_commandSetupHelper.createFirewallRulesCommands(firewallRulesIngress, domainRouterVO, cmds, null, vpcId);
|
||||||
|
}
|
||||||
|
|
||||||
protected boolean sendNetworkRulesToRouter(final long routerId, final long networkId, final boolean reprogramNetwork) throws ResourceUnavailableException {
|
protected boolean sendNetworkRulesToRouter(final long routerId, final long networkId, final boolean reprogramNetwork) throws ResourceUnavailableException {
|
||||||
final DomainRouterVO router = _routerDao.findById(routerId);
|
final DomainRouterVO router = _routerDao.findById(routerId);
|
||||||
final Commands cmds = new Commands(OnError.Continue);
|
final Commands cmds = new Commands(OnError.Continue);
|
||||||
|
|||||||
@ -36,6 +36,7 @@ import com.cloud.network.lb.LoadBalancingRulesManager;
|
|||||||
import com.cloud.network.router.VirtualRouter;
|
import com.cloud.network.router.VirtualRouter;
|
||||||
import com.cloud.network.rules.FirewallRule.Purpose;
|
import com.cloud.network.rules.FirewallRule.Purpose;
|
||||||
import com.cloud.network.rules.LoadBalancerContainer.Scheme;
|
import com.cloud.network.rules.LoadBalancerContainer.Scheme;
|
||||||
|
import com.cloud.network.vpc.Vpc;
|
||||||
import com.cloud.utils.net.Ip;
|
import com.cloud.utils.net.Ip;
|
||||||
|
|
||||||
public class FirewallRules extends RuleApplier {
|
public class FirewallRules extends RuleApplier {
|
||||||
@ -50,6 +51,16 @@ public class FirewallRules extends RuleApplier {
|
|||||||
_rules = rules;
|
_rules = rules;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public FirewallRules(final Network network, final Vpc vpc, final List<? extends FirewallRule> rules) {
|
||||||
|
super(network, vpc);
|
||||||
|
_rules = rules;
|
||||||
|
}
|
||||||
|
|
||||||
|
public FirewallRules(final Vpc vpc, final List<? extends FirewallRule> rules) {
|
||||||
|
super(null, vpc);
|
||||||
|
_rules = rules;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean accept(final NetworkTopologyVisitor visitor, final VirtualRouter router) throws ResourceUnavailableException {
|
public boolean accept(final NetworkTopologyVisitor visitor, final VirtualRouter router) throws ResourceUnavailableException {
|
||||||
_router = router;
|
_router = router;
|
||||||
|
|||||||
@ -22,6 +22,7 @@ import org.apache.cloudstack.network.topology.NetworkTopologyVisitor;
|
|||||||
import com.cloud.exception.ResourceUnavailableException;
|
import com.cloud.exception.ResourceUnavailableException;
|
||||||
import com.cloud.network.Network;
|
import com.cloud.network.Network;
|
||||||
import com.cloud.network.router.VirtualRouter;
|
import com.cloud.network.router.VirtualRouter;
|
||||||
|
import com.cloud.network.vpc.Vpc;
|
||||||
import org.apache.logging.log4j.Logger;
|
import org.apache.logging.log4j.Logger;
|
||||||
import org.apache.logging.log4j.LogManager;
|
import org.apache.logging.log4j.LogManager;
|
||||||
|
|
||||||
@ -30,16 +31,27 @@ public abstract class RuleApplier {
|
|||||||
protected Logger logger = LogManager.getLogger(getClass());
|
protected Logger logger = LogManager.getLogger(getClass());
|
||||||
|
|
||||||
protected Network _network;
|
protected Network _network;
|
||||||
|
protected Vpc _vpc;
|
||||||
protected VirtualRouter _router;
|
protected VirtualRouter _router;
|
||||||
|
|
||||||
public RuleApplier(final Network network) {
|
public RuleApplier(final Network network) {
|
||||||
_network = network;
|
_network = network;
|
||||||
|
_vpc = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public RuleApplier(final Network network, final Vpc vpc) {
|
||||||
|
_network = network;
|
||||||
|
_vpc = vpc;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Network getNetwork() {
|
public Network getNetwork() {
|
||||||
return _network;
|
return _network;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Vpc getVpc() {
|
||||||
|
return _vpc;
|
||||||
|
}
|
||||||
|
|
||||||
public VirtualRouter getRouter() {
|
public VirtualRouter getRouter() {
|
||||||
return _router;
|
return _router;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -336,7 +336,7 @@ public class VpcManagerImpl extends ManagerBase implements VpcManager, VpcProvis
|
|||||||
|
|
||||||
private final ScheduledExecutorService _executor = Executors.newScheduledThreadPool(1, new NamedThreadFactory("VpcChecker"));
|
private final ScheduledExecutorService _executor = Executors.newScheduledThreadPool(1, new NamedThreadFactory("VpcChecker"));
|
||||||
private List<VpcProvider> vpcElements = null;
|
private List<VpcProvider> vpcElements = null;
|
||||||
private final List<Service> nonSupportedServices = Arrays.asList(Service.SecurityGroup, Service.Firewall);
|
private final List<Service> nonSupportedServices = Arrays.asList(Service.SecurityGroup);
|
||||||
private final List<Provider> supportedProviders = Arrays.asList(Provider.VPCVirtualRouter, Provider.NiciraNvp, Provider.InternalLbVm, Provider.Netscaler,
|
private final List<Provider> supportedProviders = Arrays.asList(Provider.VPCVirtualRouter, Provider.NiciraNvp, Provider.InternalLbVm, Provider.Netscaler,
|
||||||
Provider.JuniperContrailVpcRouter, Provider.Ovs, Provider.BigSwitchBcf, Provider.ConfigDrive, Provider.Nsx, Provider.Netris);
|
Provider.JuniperContrailVpcRouter, Provider.Ovs, Provider.BigSwitchBcf, Provider.ConfigDrive, Provider.Nsx, Provider.Netris);
|
||||||
|
|
||||||
|
|||||||
@ -989,15 +989,15 @@ public class RoutedIpv4ManagerImpl extends ComponentLifecycleBase implements Rou
|
|||||||
@Override
|
@Override
|
||||||
public boolean isVirtualRouterGateway(Network network) {
|
public boolean isVirtualRouterGateway(Network network) {
|
||||||
return isRoutedNetwork(network)
|
return isRoutedNetwork(network)
|
||||||
&& (networkServiceMapDao.canProviderSupportServiceInNetwork(network.getId(), Service.Gateway, Provider.VirtualRouter))
|
&& (networkServiceMapDao.canProviderSupportServiceInNetwork(network.getId(), Service.Gateway, Provider.VirtualRouter)
|
||||||
|| networkServiceMapDao.canProviderSupportServiceInNetwork(network.getId(), Service.Gateway, Provider.VPCVirtualRouter);
|
|| networkServiceMapDao.canProviderSupportServiceInNetwork(network.getId(), Service.Gateway, Provider.VPCVirtualRouter));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean isVirtualRouterGateway(NetworkOffering networkOffering) {
|
public boolean isVirtualRouterGateway(NetworkOffering networkOffering) {
|
||||||
return NetworkOffering.NetworkMode.ROUTED.equals(networkOffering.getNetworkMode())
|
return NetworkOffering.NetworkMode.ROUTED.equals(networkOffering.getNetworkMode())
|
||||||
&& networkOfferingServiceMapDao.canProviderSupportServiceInNetworkOffering(networkOffering.getId(), Service.Gateway, Provider.VirtualRouter)
|
&& (networkOfferingServiceMapDao.canProviderSupportServiceInNetworkOffering(networkOffering.getId(), Service.Gateway, Provider.VirtualRouter)
|
||||||
|| networkOfferingServiceMapDao.canProviderSupportServiceInNetworkOffering(networkOffering.getId(), Service.Gateway, Provider.VPCVirtualRouter);
|
|| networkOfferingServiceMapDao.canProviderSupportServiceInNetworkOffering(networkOffering.getId(), Service.Gateway, Provider.VPCVirtualRouter));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@ -65,6 +65,7 @@ import com.cloud.network.rules.UserdataToRouterRules;
|
|||||||
import com.cloud.network.vpc.NetworkACLItem;
|
import com.cloud.network.vpc.NetworkACLItem;
|
||||||
import com.cloud.network.vpc.PrivateGateway;
|
import com.cloud.network.vpc.PrivateGateway;
|
||||||
import com.cloud.network.vpc.StaticRouteProfile;
|
import com.cloud.network.vpc.StaticRouteProfile;
|
||||||
|
import com.cloud.network.vpc.Vpc;
|
||||||
import com.cloud.utils.exception.CloudRuntimeException;
|
import com.cloud.utils.exception.CloudRuntimeException;
|
||||||
import com.cloud.vm.DomainRouterVO;
|
import com.cloud.vm.DomainRouterVO;
|
||||||
import com.cloud.vm.NicProfile;
|
import com.cloud.vm.NicProfile;
|
||||||
@ -228,6 +229,26 @@ public class BasicNetworkTopology implements NetworkTopology {
|
|||||||
return applyRules(network, router, typeString, isPodLevelException, podId, failWhenDisconnect, new RuleApplierWrapper<RuleApplier>(firewallRules));
|
return applyRules(network, router, typeString, isPodLevelException, podId, failWhenDisconnect, new RuleApplierWrapper<RuleApplier>(firewallRules));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean applyFirewallRulesInVPC(final Vpc vpc, final List<? extends FirewallRule> rules, final VirtualRouter router)
|
||||||
|
throws ResourceUnavailableException {
|
||||||
|
if (rules == null || rules.isEmpty()) {
|
||||||
|
logger.debug("No firewall rules to be applied for vpc {}", vpc);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
logger.debug("APPLYING FIREWALL RULES");
|
||||||
|
|
||||||
|
final String typeString = "firewall rules";
|
||||||
|
final boolean isPodLevelException = false;
|
||||||
|
final boolean failWhenDisconnect = false;
|
||||||
|
final Long podId = null;
|
||||||
|
|
||||||
|
final FirewallRules firewallRules = new FirewallRules(vpc, rules);
|
||||||
|
|
||||||
|
return applyRulesInVPC(vpc, router, typeString, isPodLevelException, podId, failWhenDisconnect, new RuleApplierWrapper<RuleApplier>(firewallRules));
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean applyStaticNats(final Network network, final List<? extends StaticNat> rules, final VirtualRouter router) throws ResourceUnavailableException {
|
public boolean applyStaticNats(final Network network, final List<? extends StaticNat> rules, final VirtualRouter router) throws ResourceUnavailableException {
|
||||||
if (rules == null || rules.isEmpty()) {
|
if (rules == null || rules.isEmpty()) {
|
||||||
@ -444,6 +465,102 @@ public class BasicNetworkTopology implements NetworkTopology {
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean applyRulesInVPC(final Vpc vpc, final VirtualRouter router, final String typeString, final boolean isPodLevelException, final Long podId,
|
||||||
|
final boolean failWhenDisconnect, final RuleApplierWrapper<RuleApplier> ruleApplierWrapper) throws ResourceUnavailableException {
|
||||||
|
|
||||||
|
if (vpc == null) {
|
||||||
|
throw new CloudRuntimeException("Unable to apply " + typeString + " because VPC is null");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (router == null) {
|
||||||
|
logger.warn("Unable to apply {}, virtual router doesn't exist in vpc {}", typeString, vpc);
|
||||||
|
final Long dcId = vpc.getZoneId();
|
||||||
|
throw new ResourceUnavailableException("Unable to apply " + typeString, DataCenter.class, dcId);
|
||||||
|
}
|
||||||
|
|
||||||
|
final RuleApplier ruleApplier = ruleApplierWrapper.getRuleType();
|
||||||
|
|
||||||
|
final Long dcId = vpc.getZoneId();
|
||||||
|
final DataCenter dc = _dcDao.findById(dcId);
|
||||||
|
final boolean isZoneBasic = dc.getNetworkType() == NetworkType.Basic;
|
||||||
|
|
||||||
|
// isPodLevelException and podId is only used for basic zone
|
||||||
|
assert !(!isZoneBasic && isPodLevelException || isZoneBasic && isPodLevelException && podId == null);
|
||||||
|
|
||||||
|
final List<VirtualRouter> connectedRouters = new ArrayList<VirtualRouter>();
|
||||||
|
final List<VirtualRouter> disconnectedRouters = new ArrayList<VirtualRouter>();
|
||||||
|
boolean result = true;
|
||||||
|
final String msg = "Unable to apply " + typeString + " on disconnected router ";
|
||||||
|
if (router.getState() == State.Running) {
|
||||||
|
logger.debug("Applying {} in vpc {}", typeString, vpc);
|
||||||
|
|
||||||
|
if (router.isStopPending()) {
|
||||||
|
if (_hostDao.findById(router.getHostId()).getState() == Status.Up) {
|
||||||
|
throw new ResourceUnavailableException("Unable to process due to the stop pending router " + router.getInstanceName()
|
||||||
|
+ " haven't been stopped after it's host coming back!", DataCenter.class, router.getDataCenterId());
|
||||||
|
}
|
||||||
|
logger.debug("Router {} is stop pending, so not sending apply {} commands to the backend", router, typeString);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
result = ruleApplier.accept(getVisitor(), router);
|
||||||
|
connectedRouters.add(router);
|
||||||
|
} catch (final AgentUnavailableException e) {
|
||||||
|
logger.warn("{}{}", msg, router, e);
|
||||||
|
disconnectedRouters.add(router);
|
||||||
|
}
|
||||||
|
|
||||||
|
// If rules fail to apply on one domR and not due to
|
||||||
|
// disconnection, no need to proceed with the rest
|
||||||
|
if (!result) {
|
||||||
|
if (isZoneBasic && isPodLevelException) {
|
||||||
|
throw new ResourceUnavailableException("Unable to apply " + typeString + " on router ", Pod.class, podId);
|
||||||
|
}
|
||||||
|
throw new ResourceUnavailableException("Unable to apply " + typeString + " on router ", DataCenter.class, router.getDataCenterId());
|
||||||
|
}
|
||||||
|
|
||||||
|
} else if (router.getState() == State.Stopped || router.getState() == State.Stopping) {
|
||||||
|
logger.debug("Router {} is in {}, so not sending apply {} commands to the backend", router, router.getState(), typeString);
|
||||||
|
} else {
|
||||||
|
logger.warn("Unable to apply " + typeString + ", virtual router is not in the right state " + router.getState());
|
||||||
|
if (isZoneBasic && isPodLevelException) {
|
||||||
|
throw new ResourceUnavailableException("Unable to apply " + typeString + ", virtual router is not in the right state", Pod.class, podId);
|
||||||
|
}
|
||||||
|
throw new ResourceUnavailableException("Unable to apply " + typeString + ", virtual router is not in the right state", DataCenter.class, router.getDataCenterId());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!connectedRouters.isEmpty()) {
|
||||||
|
// Shouldn't we include this check inside the method?
|
||||||
|
if (!isZoneBasic && !disconnectedRouters.isEmpty()) {
|
||||||
|
// These disconnected redundant virtual routers are out of sync
|
||||||
|
// now, stop them for synchronization
|
||||||
|
for (final VirtualRouter virtualRouter : disconnectedRouters) {
|
||||||
|
// If we have at least 1 disconnected redundant router, callhandleSingleWorkingRedundantRouter().
|
||||||
|
if (virtualRouter.getIsRedundantRouter()) {
|
||||||
|
_networkHelper.handleSingleWorkingRedundantRouter(connectedRouters, disconnectedRouters, msg);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if (!disconnectedRouters.isEmpty()) {
|
||||||
|
if (logger.isDebugEnabled()) {
|
||||||
|
logger.debug("{}{}", msg, router);
|
||||||
|
}
|
||||||
|
if (isZoneBasic && isPodLevelException) {
|
||||||
|
throw new ResourceUnavailableException(msg, Pod.class, podId);
|
||||||
|
}
|
||||||
|
throw new ResourceUnavailableException(msg, DataCenter.class, disconnectedRouters.get(0).getDataCenterId());
|
||||||
|
}
|
||||||
|
|
||||||
|
result = true;
|
||||||
|
if (failWhenDisconnect) {
|
||||||
|
result = !connectedRouters.isEmpty();
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean removeDhcpEntry(Network network, NicProfile nic, VirtualMachineProfile profile, VirtualRouter virtualRouter) throws ResourceUnavailableException {
|
public boolean removeDhcpEntry(Network network, NicProfile nic, VirtualMachineProfile profile, VirtualRouter virtualRouter) throws ResourceUnavailableException {
|
||||||
logger.debug("REMOVING DHCP ENTRY RULE");
|
logger.debug("REMOVING DHCP ENTRY RULE");
|
||||||
|
|||||||
@ -145,7 +145,9 @@ public class BasicNetworkVisitor extends NetworkTopologyVisitor {
|
|||||||
|
|
||||||
} else if (purpose == Purpose.Firewall) {
|
} else if (purpose == Purpose.Firewall) {
|
||||||
|
|
||||||
_commandSetupHelper.createApplyFirewallRulesCommands(rules, router, cmds, network.getId());
|
final Long guestNetworkId = network != null ? network.getId() : null;
|
||||||
|
final Long vpcId = network != null ? network.getVpcId() : router.getVpcId();
|
||||||
|
_commandSetupHelper.createApplyFirewallRulesCommands(rules, router, cmds, guestNetworkId, vpcId);
|
||||||
|
|
||||||
return _networkGeneralHelper.sendCommandsToRouter(router, cmds);
|
return _networkGeneralHelper.sendCommandsToRouter(router, cmds);
|
||||||
|
|
||||||
|
|||||||
@ -35,6 +35,7 @@ import com.cloud.network.rules.StaticNat;
|
|||||||
import com.cloud.network.vpc.NetworkACLItem;
|
import com.cloud.network.vpc.NetworkACLItem;
|
||||||
import com.cloud.network.vpc.PrivateGateway;
|
import com.cloud.network.vpc.PrivateGateway;
|
||||||
import com.cloud.network.vpc.StaticRouteProfile;
|
import com.cloud.network.vpc.StaticRouteProfile;
|
||||||
|
import com.cloud.network.vpc.Vpc;
|
||||||
import com.cloud.vm.DomainRouterVO;
|
import com.cloud.vm.DomainRouterVO;
|
||||||
import com.cloud.vm.NicProfile;
|
import com.cloud.vm.NicProfile;
|
||||||
import com.cloud.vm.VirtualMachineProfile;
|
import com.cloud.vm.VirtualMachineProfile;
|
||||||
@ -72,6 +73,8 @@ public interface NetworkTopology {
|
|||||||
|
|
||||||
boolean applyFirewallRules(final Network network, final List<? extends FirewallRule> rules, final VirtualRouter router) throws ResourceUnavailableException;
|
boolean applyFirewallRules(final Network network, final List<? extends FirewallRule> rules, final VirtualRouter router) throws ResourceUnavailableException;
|
||||||
|
|
||||||
|
boolean applyFirewallRulesInVPC(final Vpc vpc, final List<? extends FirewallRule> rules, final VirtualRouter router) throws ResourceUnavailableException;
|
||||||
|
|
||||||
boolean applyStaticNats(final Network network, final List<? extends StaticNat> rules, final VirtualRouter router) throws ResourceUnavailableException;
|
boolean applyStaticNats(final Network network, final List<? extends StaticNat> rules, final VirtualRouter router) throws ResourceUnavailableException;
|
||||||
|
|
||||||
boolean associatePublicIP(final Network network, final List<? extends PublicIpAddress> ipAddress, final VirtualRouter router) throws ResourceUnavailableException;
|
boolean associatePublicIP(final Network network, final List<? extends PublicIpAddress> ipAddress, final VirtualRouter router) throws ResourceUnavailableException;
|
||||||
@ -89,6 +92,9 @@ public interface NetworkTopology {
|
|||||||
boolean applyRules(final Network network, final VirtualRouter router, final String typeString, final boolean isPodLevelException, final Long podId,
|
boolean applyRules(final Network network, final VirtualRouter router, final String typeString, final boolean isPodLevelException, final Long podId,
|
||||||
final boolean failWhenDisconnect, RuleApplierWrapper<RuleApplier> ruleApplier) throws ResourceUnavailableException;
|
final boolean failWhenDisconnect, RuleApplierWrapper<RuleApplier> ruleApplier) throws ResourceUnavailableException;
|
||||||
|
|
||||||
|
boolean applyRulesInVPC(final Vpc vpc, final VirtualRouter router, final String typeString, final boolean isPodLevelException, final Long podId,
|
||||||
|
final boolean failWhenDisconnect, RuleApplierWrapper<RuleApplier> ruleApplier) throws ResourceUnavailableException;
|
||||||
|
|
||||||
boolean removeDhcpEntry(final Network network, final NicProfile nic, final VirtualMachineProfile profile, final VirtualRouter virtualRouter) throws ResourceUnavailableException;
|
boolean removeDhcpEntry(final Network network, final NicProfile nic, final VirtualMachineProfile profile, final VirtualRouter virtualRouter) throws ResourceUnavailableException;
|
||||||
|
|
||||||
boolean applyBgpPeers(final Network network, final List<? extends BgpPeer> bpgPeers, final VirtualRouter virtualRouter) throws ResourceUnavailableException;
|
boolean applyBgpPeers(final Network network, final List<? extends BgpPeer> bpgPeers, final VirtualRouter virtualRouter) throws ResourceUnavailableException;
|
||||||
|
|||||||
@ -19,10 +19,13 @@ package com.cloud.network;
|
|||||||
|
|
||||||
import static org.junit.Assert.assertFalse;
|
import static org.junit.Assert.assertFalse;
|
||||||
import static org.junit.Assert.assertTrue;
|
import static org.junit.Assert.assertTrue;
|
||||||
|
import static org.mockito.ArgumentMatchers.any;
|
||||||
|
import static org.mockito.ArgumentMatchers.anyBoolean;
|
||||||
import static org.mockito.ArgumentMatchers.anyLong;
|
import static org.mockito.ArgumentMatchers.anyLong;
|
||||||
import static org.mockito.Mockito.doReturn;
|
import static org.mockito.Mockito.doReturn;
|
||||||
import static org.mockito.Mockito.lenient;
|
import static org.mockito.Mockito.lenient;
|
||||||
import static org.mockito.Mockito.mock;
|
import static org.mockito.Mockito.mock;
|
||||||
|
import static org.mockito.Mockito.never;
|
||||||
import static org.mockito.Mockito.verify;
|
import static org.mockito.Mockito.verify;
|
||||||
import static org.mockito.Mockito.when;
|
import static org.mockito.Mockito.when;
|
||||||
|
|
||||||
@ -54,8 +57,13 @@ import com.cloud.network.dao.IPAddressDao;
|
|||||||
import com.cloud.network.dao.IPAddressVO;
|
import com.cloud.network.dao.IPAddressVO;
|
||||||
import com.cloud.network.dao.NetworkDao;
|
import com.cloud.network.dao.NetworkDao;
|
||||||
import com.cloud.network.dao.NetworkVO;
|
import com.cloud.network.dao.NetworkVO;
|
||||||
|
import com.cloud.network.rules.FirewallRule;
|
||||||
import com.cloud.network.rules.StaticNat;
|
import com.cloud.network.rules.StaticNat;
|
||||||
import com.cloud.network.rules.StaticNatImpl;
|
import com.cloud.network.rules.StaticNatImpl;
|
||||||
|
import com.cloud.network.vpc.dao.VpcDao;
|
||||||
|
import com.cloud.network.vpc.VpcVO;
|
||||||
|
import com.cloud.network.vpc.VpcManager;
|
||||||
|
import com.cloud.dc.dao.VlanDao;
|
||||||
import com.cloud.offerings.NetworkOfferingVO;
|
import com.cloud.offerings.NetworkOfferingVO;
|
||||||
import com.cloud.offerings.dao.NetworkOfferingDao;
|
import com.cloud.offerings.dao.NetworkOfferingDao;
|
||||||
import com.cloud.user.AccountVO;
|
import com.cloud.user.AccountVO;
|
||||||
@ -105,6 +113,15 @@ public class IpAddressManagerTest {
|
|||||||
@Mock
|
@Mock
|
||||||
AccountManager accountManagerMock;
|
AccountManager accountManagerMock;
|
||||||
|
|
||||||
|
@Mock
|
||||||
|
VpcManager vpcMgr;
|
||||||
|
|
||||||
|
@Mock
|
||||||
|
VpcDao vpcDao;
|
||||||
|
|
||||||
|
@Mock
|
||||||
|
VlanDao vlanDao;
|
||||||
|
|
||||||
final long dummyID = 1L;
|
final long dummyID = 1L;
|
||||||
|
|
||||||
final String UUID = "uuid";
|
final String UUID = "uuid";
|
||||||
@ -492,4 +509,135 @@ public class IpAddressManagerTest {
|
|||||||
|
|
||||||
Assert.assertTrue(result);
|
Assert.assertTrue(result);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private FirewallRule makeRule(Long networkId, Long vpcId, FirewallRule.Purpose purpose,
|
||||||
|
FirewallRule.TrafficType trafficType) {
|
||||||
|
FirewallRule rule = mock(FirewallRule.class);
|
||||||
|
lenient().when(rule.getNetworkId()).thenReturn(networkId);
|
||||||
|
lenient().when(rule.getVpcId()).thenReturn(vpcId);
|
||||||
|
lenient().when(rule.getPurpose()).thenReturn(purpose);
|
||||||
|
lenient().when(rule.getTrafficType()).thenReturn(trafficType);
|
||||||
|
return rule;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Stub the two IP-association helper methods so they are no-ops. */
|
||||||
|
private void stubIpAssocHelpers() throws ResourceUnavailableException {
|
||||||
|
doReturn(false).when(ipAddressManager).checkIfIpAssocRequired(any(Network.class), anyBoolean(), any());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test: Non-VPC rules still resolve via networkId (backward compatibility).
|
||||||
|
*/
|
||||||
|
@Test
|
||||||
|
public void applyRulesNonVpcRuleStillWorksViaNetworkId() throws ResourceUnavailableException {
|
||||||
|
long networkId = 10L;
|
||||||
|
NetworkVO network = mock(NetworkVO.class);
|
||||||
|
when(network.getId()).thenReturn(networkId);
|
||||||
|
when(networkDao.findById(networkId)).thenReturn(network);
|
||||||
|
|
||||||
|
FirewallRule rule = makeRule(networkId, null, FirewallRule.Purpose.Firewall, FirewallRule.TrafficType.Ingress);
|
||||||
|
NetworkRuleApplier applier = mock(NetworkRuleApplier.class);
|
||||||
|
|
||||||
|
when(ipAddressDao.listByAssociatedNetwork(networkId, null)).thenReturn(new ArrayList<>());
|
||||||
|
stubIpAssocHelpers();
|
||||||
|
|
||||||
|
boolean result = ipAddressManager.applyRules(
|
||||||
|
Collections.singletonList(rule), FirewallRule.Purpose.Firewall, applier, false);
|
||||||
|
|
||||||
|
assertTrue(result);
|
||||||
|
verify(networkDao).findById(networkId);
|
||||||
|
verify(applier).applyRules(network, null, FirewallRule.Purpose.Firewall, Collections.singletonList(rule));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test: VPC rule resolves network via VpcManager.getVpcNetworks()
|
||||||
|
* when networkId is null but vpcId is set.
|
||||||
|
*/
|
||||||
|
@Test
|
||||||
|
public void applyRulesVpcRuleResolvesNetworkViaVpcManager() throws ResourceUnavailableException {
|
||||||
|
long vpcId = 20L;
|
||||||
|
VpcVO vpc = mock(VpcVO.class);
|
||||||
|
when(vpcDao.findById(vpcId)).thenReturn(vpc);
|
||||||
|
|
||||||
|
FirewallRule rule = makeRule(null, vpcId, FirewallRule.Purpose.Firewall, FirewallRule.TrafficType.Ingress);
|
||||||
|
NetworkRuleApplier applier = mock(NetworkRuleApplier.class);
|
||||||
|
|
||||||
|
stubIpAssocHelpers();
|
||||||
|
|
||||||
|
boolean result = ipAddressManager.applyRules(
|
||||||
|
Collections.singletonList(rule), FirewallRule.Purpose.Firewall, applier, false);
|
||||||
|
|
||||||
|
assertTrue(result);
|
||||||
|
verify(vpcDao).findById(vpcId);
|
||||||
|
verify(applier).applyRules(null, vpc, FirewallRule.Purpose.Firewall, Collections.singletonList(rule));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test: For VPC egress firewall rules, IP collection should be skipped.
|
||||||
|
*/
|
||||||
|
@Test
|
||||||
|
public void applyRulesVpcEgressFirewallRuleSkipsIpCollection() throws ResourceUnavailableException {
|
||||||
|
long vpcId = 20L;
|
||||||
|
VpcVO vpc = mock(VpcVO.class);
|
||||||
|
when(vpcDao.findById(vpcId)).thenReturn(vpc);
|
||||||
|
|
||||||
|
FirewallRule rule = makeRule(null, vpcId, FirewallRule.Purpose.Firewall, FirewallRule.TrafficType.Egress);
|
||||||
|
NetworkRuleApplier applier = mock(NetworkRuleApplier.class);
|
||||||
|
|
||||||
|
stubIpAssocHelpers();
|
||||||
|
|
||||||
|
boolean result = ipAddressManager.applyRules(
|
||||||
|
Collections.singletonList(rule), FirewallRule.Purpose.Firewall, applier, false);
|
||||||
|
|
||||||
|
assertTrue(result);
|
||||||
|
verify(ipAddressDao, never()).listByAssociatedVpc(anyLong(), any());
|
||||||
|
verify(applier).applyRules(null, vpc, FirewallRule.Purpose.Firewall, Collections.singletonList(rule));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test: VPC ingress firewall rules collect public IPs from VPC (listByAssociatedVpc),
|
||||||
|
* NOT from network (listByAssociatedNetwork).
|
||||||
|
*/
|
||||||
|
@Test
|
||||||
|
public void applyRulesVpcIngressRuleCollectsIpsFromVpcNotNetwork() throws ResourceUnavailableException {
|
||||||
|
long vpcId = 20L;
|
||||||
|
VpcVO vpc = mock(VpcVO.class);
|
||||||
|
when(vpcDao.findById(vpcId)).thenReturn(vpc);
|
||||||
|
|
||||||
|
stubIpAssocHelpers();
|
||||||
|
|
||||||
|
NetworkRuleApplier applier = mock(NetworkRuleApplier.class);
|
||||||
|
FirewallRule rule = makeRule(null, vpcId, FirewallRule.Purpose.Firewall, FirewallRule.TrafficType.Ingress);
|
||||||
|
|
||||||
|
ipAddressManager.applyRules(Collections.singletonList(rule), FirewallRule.Purpose.Firewall, applier, false);
|
||||||
|
|
||||||
|
verify(applier).applyRules(null, vpc, FirewallRule.Purpose.Firewall, Collections.singletonList(rule));
|
||||||
|
verify(ipAddressDao, never()).listByAssociatedVpc(vpcId, null);
|
||||||
|
verify(ipAddressDao, never()).listByAssociatedNetwork(anyLong(), any());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test: Error handling respects continueOnError flag.
|
||||||
|
* When continueOnError=true, exceptions are caught and false is returned.
|
||||||
|
*/
|
||||||
|
@Test
|
||||||
|
public void applyRulesVpcRuleErrorHandlingWithContinueOnErrorTrue() throws ResourceUnavailableException {
|
||||||
|
long vpcId = 20L;
|
||||||
|
VpcVO vpc = mock(VpcVO.class);
|
||||||
|
when(vpcDao.findById(vpcId)).thenReturn(vpc);
|
||||||
|
|
||||||
|
stubIpAssocHelpers();
|
||||||
|
|
||||||
|
NetworkRuleApplier applier = mock(NetworkRuleApplier.class);
|
||||||
|
when(applier.applyRules(any(), any(), any(), any())).thenThrow(new ResourceUnavailableException("test", Network.class, 0L));
|
||||||
|
|
||||||
|
FirewallRule rule = makeRule(null, vpcId, FirewallRule.Purpose.Firewall, FirewallRule.TrafficType.Ingress);
|
||||||
|
|
||||||
|
boolean result = ipAddressManager.applyRules(
|
||||||
|
Collections.singletonList(rule), FirewallRule.Purpose.Firewall, applier, true);
|
||||||
|
|
||||||
|
assertFalse(result);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -19,10 +19,13 @@ package com.cloud.network.element;
|
|||||||
import com.cloud.dc.DataCenterVO;
|
import com.cloud.dc.DataCenterVO;
|
||||||
import com.cloud.dc.dao.DataCenterDao;
|
import com.cloud.dc.dao.DataCenterDao;
|
||||||
import com.cloud.exception.ResourceUnavailableException;
|
import com.cloud.exception.ResourceUnavailableException;
|
||||||
|
import com.cloud.network.Network;
|
||||||
|
import com.cloud.network.NetworkModel;
|
||||||
import com.cloud.network.RemoteAccessVpn;
|
import com.cloud.network.RemoteAccessVpn;
|
||||||
import com.cloud.network.VpnUser;
|
import com.cloud.network.VpnUser;
|
||||||
import com.cloud.network.router.VpcVirtualNetworkApplianceManagerImpl;
|
import com.cloud.network.router.VpcVirtualNetworkApplianceManagerImpl;
|
||||||
import com.cloud.network.vpc.Vpc;
|
import com.cloud.network.vpc.Vpc;
|
||||||
|
import com.cloud.network.vpc.VpcManager;
|
||||||
import com.cloud.network.vpc.dao.VpcDao;
|
import com.cloud.network.vpc.dao.VpcDao;
|
||||||
import com.cloud.utils.db.EntityManager;
|
import com.cloud.utils.db.EntityManager;
|
||||||
import com.cloud.vm.DomainRouterVO;
|
import com.cloud.vm.DomainRouterVO;
|
||||||
@ -43,7 +46,9 @@ import java.util.List;
|
|||||||
import static org.junit.Assert.assertEquals;
|
import static org.junit.Assert.assertEquals;
|
||||||
import static org.junit.Assert.assertNotNull;
|
import static org.junit.Assert.assertNotNull;
|
||||||
import static org.junit.Assert.assertNull;
|
import static org.junit.Assert.assertNull;
|
||||||
|
import static org.junit.Assert.assertTrue;
|
||||||
import static org.junit.Assert.fail;
|
import static org.junit.Assert.fail;
|
||||||
|
import static org.mockito.Mockito.never;
|
||||||
import static org.mockito.Mockito.times;
|
import static org.mockito.Mockito.times;
|
||||||
import static org.mockito.Mockito.verify;
|
import static org.mockito.Mockito.verify;
|
||||||
import static org.mockito.Mockito.when;
|
import static org.mockito.Mockito.when;
|
||||||
@ -60,6 +65,12 @@ public class VpcVirtualRouterElementTest {
|
|||||||
@Mock
|
@Mock
|
||||||
EntityManager _entityMgr;
|
EntityManager _entityMgr;
|
||||||
|
|
||||||
|
@Mock
|
||||||
|
NetworkModel _networkMdl;
|
||||||
|
|
||||||
|
@Mock
|
||||||
|
VpcManager _vpcMgr;
|
||||||
|
|
||||||
@Mock
|
@Mock
|
||||||
NetworkTopologyContext networkTopologyContext;
|
NetworkTopologyContext networkTopologyContext;
|
||||||
|
|
||||||
@ -188,4 +199,19 @@ public class VpcVirtualRouterElementTest {
|
|||||||
|
|
||||||
verify(remoteAccessVpn, times(1)).getVpcId();
|
verify(remoteAccessVpn, times(1)).getVpcId();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testCanHandleFirewallUsesVpcCapability() {
|
||||||
|
final Network network = Mockito.mock(Network.class);
|
||||||
|
|
||||||
|
when(_networkMdl.getPhysicalNetworkId(network)).thenReturn(1L);
|
||||||
|
when(network.getId()).thenReturn(200L);
|
||||||
|
when(network.getVpcId()).thenReturn(100L);
|
||||||
|
when(_networkMdl.isProviderEnabledInPhysicalNetwork(1L, Network.Provider.VPCVirtualRouter.getName())).thenReturn(true);
|
||||||
|
when(_networkMdl.isProviderSupportServiceInNetwork(200L, Network.Service.Firewall, Network.Provider.VPCVirtualRouter)).thenReturn(true);
|
||||||
|
|
||||||
|
assertTrue(vpcVirtualRouterElement.canHandle(network, Network.Service.Firewall));
|
||||||
|
verify(_networkMdl).isProviderSupportServiceInNetwork(200L, Network.Service.Firewall, Network.Provider.VPCVirtualRouter);
|
||||||
|
verify(_vpcMgr, never()).isProviderSupportServiceInVpc(100L, Network.Service.Firewall, Network.Provider.VPCVirtualRouter);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -17,27 +17,36 @@
|
|||||||
|
|
||||||
package com.cloud.network.firewall;
|
package com.cloud.network.firewall;
|
||||||
|
|
||||||
|
import com.cloud.exception.InvalidParameterValueException;
|
||||||
import com.cloud.exception.NetworkRuleConflictException;
|
import com.cloud.exception.NetworkRuleConflictException;
|
||||||
import com.cloud.exception.ResourceUnavailableException;
|
import com.cloud.exception.ResourceUnavailableException;
|
||||||
import com.cloud.network.IpAddressManager;
|
import com.cloud.network.IpAddressManager;
|
||||||
import com.cloud.network.Network;
|
import com.cloud.network.Network;
|
||||||
|
import com.cloud.network.Network.Capability;
|
||||||
|
import com.cloud.network.Network.Service;
|
||||||
import com.cloud.network.NetworkModel;
|
import com.cloud.network.NetworkModel;
|
||||||
import com.cloud.network.NetworkRuleApplier;
|
import com.cloud.network.NetworkRuleApplier;
|
||||||
import com.cloud.network.dao.FirewallRulesDao;
|
import com.cloud.network.dao.FirewallRulesDao;
|
||||||
|
import com.cloud.network.dao.IPAddressDao;
|
||||||
|
import com.cloud.network.dao.IPAddressVO;
|
||||||
import com.cloud.network.dao.NetworkDao;
|
import com.cloud.network.dao.NetworkDao;
|
||||||
import com.cloud.network.dao.NetworkVO;
|
import com.cloud.network.dao.NetworkVO;
|
||||||
import com.cloud.network.element.FirewallServiceProvider;
|
import com.cloud.network.element.FirewallServiceProvider;
|
||||||
import com.cloud.network.element.VirtualRouterElement;
|
import com.cloud.network.element.VirtualRouterElement;
|
||||||
import com.cloud.network.element.VpcVirtualRouterElement;
|
import com.cloud.network.element.VpcVirtualRouterElement;
|
||||||
import com.cloud.network.rules.FirewallRule;
|
import com.cloud.network.rules.FirewallRule;
|
||||||
|
import com.cloud.network.rules.FirewallRule.FirewallRuleType;
|
||||||
import com.cloud.network.rules.FirewallRule.Purpose;
|
import com.cloud.network.rules.FirewallRule.Purpose;
|
||||||
import com.cloud.network.rules.FirewallRuleVO;
|
import com.cloud.network.rules.FirewallRuleVO;
|
||||||
import com.cloud.network.vpc.Vpc;
|
import com.cloud.network.vpc.Vpc;
|
||||||
import com.cloud.network.vpc.VpcManager;
|
import com.cloud.network.vpc.VpcManager;
|
||||||
|
import com.cloud.user.Account;
|
||||||
import com.cloud.user.AccountManager;
|
import com.cloud.user.AccountManager;
|
||||||
import com.cloud.user.DomainManager;
|
import com.cloud.user.DomainManager;
|
||||||
import com.cloud.utils.component.ComponentContext;
|
import com.cloud.utils.component.ComponentContext;
|
||||||
|
import com.cloud.utils.exception.CloudRuntimeException;
|
||||||
import org.apache.cloudstack.engine.orchestration.service.NetworkOrchestrationService;
|
import org.apache.cloudstack.engine.orchestration.service.NetworkOrchestrationService;
|
||||||
|
import org.apache.cloudstack.network.RoutedIpv4Manager;
|
||||||
import org.junit.After;
|
import org.junit.After;
|
||||||
import org.junit.Assert;
|
import org.junit.Assert;
|
||||||
import org.junit.Before;
|
import org.junit.Before;
|
||||||
@ -53,12 +62,18 @@ import org.mockito.junit.MockitoJUnitRunner;
|
|||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.HashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
import static org.mockito.ArgumentMatchers.any;
|
import static org.mockito.ArgumentMatchers.any;
|
||||||
import static org.mockito.ArgumentMatchers.anyBoolean;
|
import static org.mockito.ArgumentMatchers.anyBoolean;
|
||||||
|
import static org.mockito.Mockito.doReturn;
|
||||||
import static org.mockito.Mockito.mock;
|
import static org.mockito.Mockito.mock;
|
||||||
|
import static org.mockito.Mockito.never;
|
||||||
import static org.mockito.Mockito.spy;
|
import static org.mockito.Mockito.spy;
|
||||||
|
import static org.mockito.Mockito.times;
|
||||||
import static org.mockito.Mockito.verify;
|
import static org.mockito.Mockito.verify;
|
||||||
import static org.mockito.Mockito.when;
|
import static org.mockito.Mockito.when;
|
||||||
|
|
||||||
@ -79,9 +94,13 @@ public class FirewallManagerTest {
|
|||||||
@Mock
|
@Mock
|
||||||
IpAddressManager _ipAddrMgr;
|
IpAddressManager _ipAddrMgr;
|
||||||
@Mock
|
@Mock
|
||||||
|
RoutedIpv4Manager routedIpv4Manager;
|
||||||
|
@Mock
|
||||||
FirewallRulesDao _firewallDao;
|
FirewallRulesDao _firewallDao;
|
||||||
@Mock
|
@Mock
|
||||||
NetworkDao _networkDao;
|
NetworkDao _networkDao;
|
||||||
|
@Mock
|
||||||
|
IPAddressDao _ipAddressDao;
|
||||||
|
|
||||||
@Spy
|
@Spy
|
||||||
@InjectMocks
|
@InjectMocks
|
||||||
@ -115,7 +134,7 @@ public class FirewallManagerTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private FirewallRule createFirewallRule(int startPort, int endPort, Purpose purpose) {
|
private FirewallRule createFirewallRule(int startPort, int endPort, Purpose purpose) {
|
||||||
return new FirewallRuleVO("xid", 1L, startPort, endPort, "TCP", 2, 3, 4, purpose, new ArrayList<>(),
|
return new FirewallRuleVO("xid", 1L, startPort, endPort, "TCP", 2L, 3, 4, purpose, new ArrayList<>(),
|
||||||
new ArrayList<>(), 5, 6, null, FirewallRule.TrafficType.Ingress);
|
new ArrayList<>(), 5, 6, null, FirewallRule.TrafficType.Ingress);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -332,4 +351,376 @@ public class FirewallManagerTest {
|
|||||||
|
|
||||||
Assert.assertFalse(result);
|
Assert.assertFalse(result);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testValidateFirewallRuleVpcWithoutAssociatedNetworkUsesVpcCapabilities() {
|
||||||
|
final Account caller = Mockito.mock(Account.class);
|
||||||
|
final IPAddressVO ipAddress = Mockito.mock(IPAddressVO.class);
|
||||||
|
final NetworkVO network = Mockito.mock(NetworkVO.class);
|
||||||
|
final FirewallServiceProvider firewallServiceProvider = Mockito.mock(FirewallServiceProvider.class);
|
||||||
|
final Map<Capability, String> firewallCaps = new HashMap<>();
|
||||||
|
final Map<Service, Map<Capability, String>> capabilities = new HashMap<>();
|
||||||
|
|
||||||
|
firewallCaps.put(Capability.SupportedTrafficDirection, "ingress, egress");
|
||||||
|
firewallCaps.put(Capability.SupportedProtocols, "tcp,udp,icmp");
|
||||||
|
firewallCaps.put(Capability.SupportedEgressProtocols, "tcp,udp,icmp");
|
||||||
|
capabilities.put(Service.Firewall, firewallCaps);
|
||||||
|
|
||||||
|
when(ipAddress.getVpcId()).thenReturn(10L);
|
||||||
|
when(_networkModel.getNetwork(2L)).thenReturn(network);
|
||||||
|
when(network.getVpcId()).thenReturn(10L);
|
||||||
|
when(routedIpv4Manager.isVirtualRouterGateway(network)).thenReturn(false);
|
||||||
|
when(firewallServiceProvider.getProvider()).thenReturn(Network.Provider.VPCVirtualRouter);
|
||||||
|
when(firewallServiceProvider.getCapabilities()).thenReturn(capabilities);
|
||||||
|
when(_vpcMgr.isProviderSupportServiceInVpc(10L, Service.Firewall, Network.Provider.VPCVirtualRouter)).thenReturn(true);
|
||||||
|
_firewallMgr._firewallElements = List.of(firewallServiceProvider);
|
||||||
|
|
||||||
|
_firewallMgr.validateFirewallRule(caller, ipAddress, 80, 80, "tcp", Purpose.Firewall, FirewallRuleType.User, 2L, FirewallRule.TrafficType.Ingress);
|
||||||
|
|
||||||
|
verify(_networkModel, Mockito.never()).getNetworkServiceCapabilities(Mockito.anyLong(), Mockito.eq(Service.Firewall));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testIsVpcIpAddressReturnsTrueWhenVpcIdPresent() {
|
||||||
|
IPAddressVO ipAddress = Mockito.mock(IPAddressVO.class);
|
||||||
|
when(ipAddress.getVpcId()).thenReturn(5L);
|
||||||
|
Assert.assertTrue(_firewallMgr.isVpcIpAddress(ipAddress));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testIsVpcIpAddressReturnsFalseWhenVpcIdNull() {
|
||||||
|
IPAddressVO ipAddress = Mockito.mock(IPAddressVO.class);
|
||||||
|
when(ipAddress.getVpcId()).thenReturn(null);
|
||||||
|
Assert.assertFalse(_firewallMgr.isVpcIpAddress(ipAddress));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testValidateFirewallRuleForIsolatedIpReturnsNetworkId() {
|
||||||
|
IPAddressVO ipAddress = Mockito.mock(IPAddressVO.class);
|
||||||
|
when(ipAddress.getAssociatedWithNetworkId()).thenReturn(42L);
|
||||||
|
Long result = _firewallMgr.validateFirewallRuleForIsolatedIp(ipAddress);
|
||||||
|
Assert.assertEquals(Long.valueOf(42L), result);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test(expected = InvalidParameterValueException.class)
|
||||||
|
public void testValidateFirewallRuleForIsolatedIpThrowsWhenNotAssociated() {
|
||||||
|
IPAddressVO ipAddress = Mockito.mock(IPAddressVO.class);
|
||||||
|
when(ipAddress.getAssociatedWithNetworkId()).thenReturn(null);
|
||||||
|
_firewallMgr.validateFirewallRuleForIsolatedIp(ipAddress);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testValidateFirewallRuleForVpcIpReturnsNetworkId() {
|
||||||
|
IPAddressVO ipAddress = Mockito.mock(IPAddressVO.class);
|
||||||
|
Long result = _firewallMgr.validateFirewallRuleForVpcIp(ipAddress, 99L);
|
||||||
|
Assert.assertEquals(Long.valueOf(99L), result);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test(expected = InvalidParameterValueException.class)
|
||||||
|
public void testValidateFirewallRuleForVpcIpThrowsWhenNetworkIdNull() {
|
||||||
|
IPAddressVO ipAddress = Mockito.mock(IPAddressVO.class);
|
||||||
|
_firewallMgr.validateFirewallRuleForVpcIp(ipAddress, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testGetFirewallServiceCapabilitiesForNonVpcNetworkUsesNetworkModel() {
|
||||||
|
NetworkVO network = Mockito.mock(NetworkVO.class);
|
||||||
|
when(network.getId()).thenReturn(1L);
|
||||||
|
when(network.getVpcId()).thenReturn(null);
|
||||||
|
Map<Capability, String> caps = new HashMap<>();
|
||||||
|
caps.put(Capability.SupportedProtocols, "tcp,udp");
|
||||||
|
when(_networkModel.getNetworkServiceCapabilities(1L, Service.Firewall)).thenReturn(caps);
|
||||||
|
|
||||||
|
Map<Network.Capability, String> result = _firewallMgr.getFirewallServiceCapabilities(network);
|
||||||
|
|
||||||
|
Assert.assertEquals(caps, result);
|
||||||
|
verify(_networkModel, times(1)).getNetworkServiceCapabilities(1L, Service.Firewall);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testGetFirewallServiceCapabilitiesForVpcNetworkUsesVpcProvider() {
|
||||||
|
NetworkVO network = Mockito.mock(NetworkVO.class);
|
||||||
|
FirewallServiceProvider fwProvider = Mockito.mock(FirewallServiceProvider.class);
|
||||||
|
Map<Capability, String> firewallCaps = new HashMap<>();
|
||||||
|
firewallCaps.put(Capability.SupportedProtocols, "tcp,udp,icmp");
|
||||||
|
Map<Service, Map<Capability, String>> providerCapabilities = new HashMap<>();
|
||||||
|
providerCapabilities.put(Service.Firewall, firewallCaps);
|
||||||
|
|
||||||
|
when(network.getVpcId()).thenReturn(10L);
|
||||||
|
when(fwProvider.getProvider()).thenReturn(Network.Provider.VPCVirtualRouter);
|
||||||
|
when(fwProvider.getCapabilities()).thenReturn(providerCapabilities);
|
||||||
|
when(_vpcMgr.isProviderSupportServiceInVpc(10L, Service.Firewall, Network.Provider.VPCVirtualRouter)).thenReturn(true);
|
||||||
|
_firewallMgr._firewallElements = List.of(fwProvider);
|
||||||
|
|
||||||
|
Map<Network.Capability, String> result = _firewallMgr.getFirewallServiceCapabilities(network);
|
||||||
|
|
||||||
|
Assert.assertEquals(firewallCaps, result);
|
||||||
|
verify(_networkModel, never()).getNetworkServiceCapabilities(Mockito.anyLong(), Mockito.eq(Service.Firewall));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testGetFirewallServiceCapabilitiesForVpcNetworkFallsBackToNetworkModelWhenNoProvider() {
|
||||||
|
NetworkVO network = Mockito.mock(NetworkVO.class);
|
||||||
|
FirewallServiceProvider fwProvider = Mockito.mock(FirewallServiceProvider.class);
|
||||||
|
Map<Capability, String> fallbackCaps = new HashMap<>();
|
||||||
|
|
||||||
|
when(network.getId()).thenReturn(1L);
|
||||||
|
when(network.getVpcId()).thenReturn(10L);
|
||||||
|
when(fwProvider.getProvider()).thenReturn(Network.Provider.VPCVirtualRouter);
|
||||||
|
when(_vpcMgr.isProviderSupportServiceInVpc(10L, Service.Firewall, Network.Provider.VPCVirtualRouter)).thenReturn(false);
|
||||||
|
when(_networkModel.getNetworkServiceCapabilities(1L, Service.Firewall)).thenReturn(fallbackCaps);
|
||||||
|
_firewallMgr._firewallElements = List.of(fwProvider);
|
||||||
|
|
||||||
|
Map<Network.Capability, String> result = _firewallMgr.getFirewallServiceCapabilities(network);
|
||||||
|
|
||||||
|
Assert.assertEquals(fallbackCaps, result);
|
||||||
|
verify(_networkModel, times(1)).getNetworkServiceCapabilities(1L, Service.Firewall);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testGetFirewallServiceCapabilitiesForVpcReturnsCapabilitiesWhenProviderSupports() {
|
||||||
|
FirewallServiceProvider fwProvider = Mockito.mock(FirewallServiceProvider.class);
|
||||||
|
Map<Capability, String> firewallCaps = new HashMap<>();
|
||||||
|
firewallCaps.put(Capability.SupportedProtocols, "tcp,udp");
|
||||||
|
Map<Service, Map<Capability, String>> caps = new HashMap<>();
|
||||||
|
caps.put(Service.Firewall, firewallCaps);
|
||||||
|
|
||||||
|
when(fwProvider.getProvider()).thenReturn(Network.Provider.VPCVirtualRouter);
|
||||||
|
when(fwProvider.getCapabilities()).thenReturn(caps);
|
||||||
|
when(_vpcMgr.isProviderSupportServiceInVpc(10L, Service.Firewall, Network.Provider.VPCVirtualRouter)).thenReturn(true);
|
||||||
|
_firewallMgr._firewallElements = List.of(fwProvider);
|
||||||
|
|
||||||
|
Map<Network.Capability, String> result = _firewallMgr.getFirewallServiceCapabilitiesForVpc(10L);
|
||||||
|
|
||||||
|
Assert.assertNotNull(result);
|
||||||
|
Assert.assertEquals("tcp,udp", result.get(Capability.SupportedProtocols));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testGetFirewallServiceCapabilitiesForVpcReturnsNullWhenNoProviderSupports() {
|
||||||
|
FirewallServiceProvider fwProvider = Mockito.mock(FirewallServiceProvider.class);
|
||||||
|
when(fwProvider.getProvider()).thenReturn(Network.Provider.VPCVirtualRouter);
|
||||||
|
when(_vpcMgr.isProviderSupportServiceInVpc(10L, Service.Firewall, Network.Provider.VPCVirtualRouter)).thenReturn(false);
|
||||||
|
_firewallMgr._firewallElements = List.of(fwProvider);
|
||||||
|
|
||||||
|
Map<Network.Capability, String> result = _firewallMgr.getFirewallServiceCapabilitiesForVpc(10L);
|
||||||
|
|
||||||
|
Assert.assertNull(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test(expected = InvalidParameterValueException.class)
|
||||||
|
public void testValidateFirewallRuleForVpcThrowsOnInvalidStartPort() {
|
||||||
|
Account caller = Mockito.mock(Account.class);
|
||||||
|
_firewallMgr.validateFirewallRuleForVpc(caller, null, -1, 80, "tcp", Purpose.Firewall, FirewallRuleType.User, 10L, FirewallRule.TrafficType.Ingress);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test(expected = InvalidParameterValueException.class)
|
||||||
|
public void testValidateFirewallRuleForVpcThrowsOnInvalidEndPort() {
|
||||||
|
Account caller = Mockito.mock(Account.class);
|
||||||
|
_firewallMgr.validateFirewallRuleForVpc(caller, null, 80, 70000, "tcp", Purpose.Firewall, FirewallRuleType.User, 10L, FirewallRule.TrafficType.Ingress);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test(expected = InvalidParameterValueException.class)
|
||||||
|
public void testValidateFirewallRuleForVpcThrowsWhenStartPortGreaterThanEndPort() {
|
||||||
|
Account caller = Mockito.mock(Account.class);
|
||||||
|
_firewallMgr.validateFirewallRuleForVpc(caller, null, 200, 100, "tcp", Purpose.Firewall, FirewallRuleType.User, 10L, FirewallRule.TrafficType.Ingress);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testValidateFirewallRuleForVpcSystemTypeWithNullIpReturnsEarly() {
|
||||||
|
// System rule type + null IP should return without further validation
|
||||||
|
Account caller = Mockito.mock(Account.class);
|
||||||
|
// Should not throw even though vpcId checks come after this
|
||||||
|
_firewallMgr.validateFirewallRuleForVpc(caller, null, 80, 80, "tcp", Purpose.Firewall, FirewallRuleType.System, 10L, FirewallRule.TrafficType.Ingress);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test(expected = InvalidParameterValueException.class)
|
||||||
|
public void testValidateFirewallRuleForVpcThrowsWhenVpcIdNullAndNotSystemRule() {
|
||||||
|
Account caller = Mockito.mock(Account.class);
|
||||||
|
IPAddressVO ipAddress = Mockito.mock(IPAddressVO.class);
|
||||||
|
_firewallMgr.validateFirewallRuleForVpc(caller, ipAddress, 80, 80, "tcp", Purpose.Firewall, FirewallRuleType.User, null, FirewallRule.TrafficType.Ingress);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test(expected = InvalidParameterValueException.class)
|
||||||
|
public void testValidateFirewallRuleForVpcThrowsWhenActiveVpcNotFound() {
|
||||||
|
Account caller = Mockito.mock(Account.class);
|
||||||
|
IPAddressVO ipAddress = Mockito.mock(IPAddressVO.class);
|
||||||
|
when(_vpcMgr.getActiveVpc(10L)).thenReturn(null);
|
||||||
|
_firewallMgr.validateFirewallRuleForVpc(caller, ipAddress, 80, 80, "tcp", Purpose.Firewall, FirewallRuleType.User, 10L, FirewallRule.TrafficType.Ingress);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test(expected = InvalidParameterValueException.class)
|
||||||
|
public void testValidateFirewallRuleForVpcThrowsWhenFirewallServiceNotSupported() {
|
||||||
|
Account caller = Mockito.mock(Account.class);
|
||||||
|
IPAddressVO ipAddress = Mockito.mock(IPAddressVO.class);
|
||||||
|
Vpc vpc = Mockito.mock(Vpc.class);
|
||||||
|
when(_vpcMgr.getActiveVpc(10L)).thenReturn(vpc);
|
||||||
|
_firewallMgr._firewallElements = Collections.emptyList();
|
||||||
|
|
||||||
|
_firewallMgr.validateFirewallRuleForVpc(caller, ipAddress, 80, 80, "tcp", Purpose.Firewall, FirewallRuleType.User, 10L, FirewallRule.TrafficType.Ingress);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test(expected = InvalidParameterValueException.class)
|
||||||
|
public void testValidateFirewallRuleForVpcThrowsOnUnsupportedProtocol() {
|
||||||
|
Account caller = Mockito.mock(Account.class);
|
||||||
|
IPAddressVO ipAddress = Mockito.mock(IPAddressVO.class);
|
||||||
|
Vpc vpc = Mockito.mock(Vpc.class);
|
||||||
|
FirewallServiceProvider fwProvider = Mockito.mock(FirewallServiceProvider.class);
|
||||||
|
Map<Capability, String> firewallCaps = new HashMap<>();
|
||||||
|
firewallCaps.put(Capability.SupportedProtocols, "tcp,udp");
|
||||||
|
firewallCaps.put(Capability.SupportedTrafficDirection, "ingress,egress");
|
||||||
|
Map<Service, Map<Capability, String>> caps = new HashMap<>();
|
||||||
|
caps.put(Service.Firewall, firewallCaps);
|
||||||
|
|
||||||
|
when(_vpcMgr.getActiveVpc(10L)).thenReturn(vpc);
|
||||||
|
when(fwProvider.getProvider()).thenReturn(Network.Provider.VPCVirtualRouter);
|
||||||
|
when(fwProvider.getCapabilities()).thenReturn(caps);
|
||||||
|
when(_vpcMgr.isProviderSupportServiceInVpc(10L, Service.Firewall, Network.Provider.VPCVirtualRouter)).thenReturn(true);
|
||||||
|
_firewallMgr._firewallElements = List.of(fwProvider);
|
||||||
|
|
||||||
|
_firewallMgr.validateFirewallRuleForVpc(caller, ipAddress, 80, 80, "gre", Purpose.Firewall, FirewallRuleType.User, 10L, FirewallRule.TrafficType.Ingress);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testValidateFirewallRuleForVpcSucceedsWithSupportedProtocolAndTrafficType() {
|
||||||
|
Account caller = Mockito.mock(Account.class);
|
||||||
|
IPAddressVO ipAddress = Mockito.mock(IPAddressVO.class);
|
||||||
|
Vpc vpc = Mockito.mock(Vpc.class);
|
||||||
|
FirewallServiceProvider fwProvider = Mockito.mock(FirewallServiceProvider.class);
|
||||||
|
Map<Capability, String> firewallCaps = new HashMap<>();
|
||||||
|
firewallCaps.put(Capability.SupportedProtocols, "tcp,udp,icmp");
|
||||||
|
firewallCaps.put(Capability.SupportedTrafficDirection, "ingress,egress");
|
||||||
|
Map<Service, Map<Capability, String>> caps = new HashMap<>();
|
||||||
|
caps.put(Service.Firewall, firewallCaps);
|
||||||
|
|
||||||
|
when(_vpcMgr.getActiveVpc(10L)).thenReturn(vpc);
|
||||||
|
when(fwProvider.getProvider()).thenReturn(Network.Provider.VPCVirtualRouter);
|
||||||
|
when(fwProvider.getCapabilities()).thenReturn(caps);
|
||||||
|
when(_vpcMgr.isProviderSupportServiceInVpc(10L, Service.Firewall, Network.Provider.VPCVirtualRouter)).thenReturn(true);
|
||||||
|
_firewallMgr._firewallElements = List.of(fwProvider);
|
||||||
|
|
||||||
|
// Should not throw
|
||||||
|
_firewallMgr.validateFirewallRuleForVpc(caller, ipAddress, 80, 80, "tcp", Purpose.Firewall, FirewallRuleType.User, 10L, FirewallRule.TrafficType.Ingress);
|
||||||
|
|
||||||
|
verify(_accountMgr, times(1)).checkAccess(caller, null, true, ipAddress);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testCreateFirewallRuleRoutesToVpcWhenVpcIdProvided() throws NetworkRuleConflictException {
|
||||||
|
Account caller = Mockito.mock(Account.class);
|
||||||
|
FirewallRule vpcRule = Mockito.mock(FirewallRule.class);
|
||||||
|
|
||||||
|
doReturn(vpcRule).when(_firewallMgr).createFirewallRuleForVpc(
|
||||||
|
Mockito.anyLong(), Mockito.eq(caller), Mockito.any(), Mockito.anyInt(), Mockito.anyInt(),
|
||||||
|
Mockito.anyString(), Mockito.any(), Mockito.any(), Mockito.any(), Mockito.any(),
|
||||||
|
Mockito.any(), Mockito.any(FirewallRuleType.class), Mockito.anyLong(),
|
||||||
|
Mockito.any(FirewallRule.TrafficType.class), Mockito.anyBoolean());
|
||||||
|
|
||||||
|
_firewallMgr.createFirewallRule(1L, caller, "xid", 80, 80, "tcp",
|
||||||
|
Collections.singletonList("0.0.0.0/0"), null, null, null, null,
|
||||||
|
FirewallRuleType.User, null, 10L, FirewallRule.TrafficType.Ingress, true);
|
||||||
|
|
||||||
|
verify(_firewallMgr, times(1)).createFirewallRuleForVpc(
|
||||||
|
Mockito.anyLong(), Mockito.eq(caller), Mockito.any(), Mockito.anyInt(), Mockito.anyInt(),
|
||||||
|
Mockito.anyString(), Mockito.any(), Mockito.any(), Mockito.any(), Mockito.any(),
|
||||||
|
Mockito.any(), Mockito.any(FirewallRuleType.class), Mockito.anyLong(),
|
||||||
|
Mockito.any(FirewallRule.TrafficType.class), Mockito.anyBoolean());
|
||||||
|
|
||||||
|
verify(_firewallMgr, never()).createFirewallRuleForNonVPC(
|
||||||
|
Mockito.any(), Mockito.any(), Mockito.any(), Mockito.any(), Mockito.any(),
|
||||||
|
Mockito.any(), Mockito.any(), Mockito.any(), Mockito.any(), Mockito.any(),
|
||||||
|
Mockito.any(), Mockito.any(), Mockito.any(), Mockito.any(), Mockito.any());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testCreateFirewallRuleRoutesToNonVpcWhenVpcIdNull() throws NetworkRuleConflictException {
|
||||||
|
Account caller = Mockito.mock(Account.class);
|
||||||
|
FirewallRule nonVpcRule = Mockito.mock(FirewallRule.class);
|
||||||
|
|
||||||
|
doReturn(nonVpcRule).when(_firewallMgr).createFirewallRuleForNonVPC(
|
||||||
|
Mockito.any(), Mockito.eq(caller), Mockito.any(), Mockito.any(), Mockito.any(),
|
||||||
|
Mockito.anyString(), Mockito.any(), Mockito.any(), Mockito.any(), Mockito.any(),
|
||||||
|
Mockito.any(), Mockito.any(FirewallRuleType.class), Mockito.anyLong(),
|
||||||
|
Mockito.any(FirewallRule.TrafficType.class), Mockito.anyBoolean());
|
||||||
|
|
||||||
|
_firewallMgr.createFirewallRule(null, caller, "xid", 80, 80, "tcp",
|
||||||
|
Collections.singletonList("0.0.0.0/0"), null, null, null, null,
|
||||||
|
FirewallRuleType.User, 2L, null, FirewallRule.TrafficType.Ingress, true);
|
||||||
|
|
||||||
|
verify(_firewallMgr, times(1)).createFirewallRuleForNonVPC(
|
||||||
|
Mockito.any(), Mockito.eq(caller), Mockito.any(), Mockito.any(), Mockito.any(),
|
||||||
|
Mockito.anyString(), Mockito.any(), Mockito.any(), Mockito.any(), Mockito.any(),
|
||||||
|
Mockito.any(), Mockito.any(FirewallRuleType.class), Mockito.anyLong(),
|
||||||
|
Mockito.any(FirewallRule.TrafficType.class), Mockito.anyBoolean());
|
||||||
|
|
||||||
|
verify(_firewallMgr, never()).createFirewallRuleForVpc(
|
||||||
|
Mockito.any(), Mockito.any(), Mockito.any(), Mockito.any(), Mockito.any(),
|
||||||
|
Mockito.any(), Mockito.any(), Mockito.any(), Mockito.any(), Mockito.any(),
|
||||||
|
Mockito.any(), Mockito.any(), Mockito.any(), Mockito.any(), Mockito.any());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testApplyRulesForVpcNetworkUsesVpcProviderCheck() throws ResourceUnavailableException {
|
||||||
|
FirewallManagerImpl firewallMgr = new FirewallManagerImpl();
|
||||||
|
firewallMgr._networkModel = _networkModel;
|
||||||
|
firewallMgr._vpcMgr = _vpcMgr;
|
||||||
|
|
||||||
|
Network network = Mockito.mock(Network.class);
|
||||||
|
FirewallServiceProvider fwProvider = Mockito.mock(FirewallServiceProvider.class);
|
||||||
|
List<FirewallRule> rules = new ArrayList<>();
|
||||||
|
FirewallRuleVO rule = new FirewallRuleVO("rule1", 1L, 80, 80, "tcp", 1L, 2, 3, Purpose.Firewall,
|
||||||
|
Collections.emptyList(), Collections.emptyList(), null, null, null, FirewallRule.TrafficType.Ingress);
|
||||||
|
rules.add(rule);
|
||||||
|
|
||||||
|
when(network.getVpcId()).thenReturn(10L);
|
||||||
|
when(fwProvider.getProvider()).thenReturn(Network.Provider.VPCVirtualRouter);
|
||||||
|
when(_vpcMgr.isProviderSupportServiceInVpc(10L, Service.Firewall, Network.Provider.VPCVirtualRouter)).thenReturn(true);
|
||||||
|
when(fwProvider.applyFWRules(Mockito.eq(network), Mockito.anyList())).thenReturn(true);
|
||||||
|
firewallMgr._firewallElements = List.of(fwProvider);
|
||||||
|
|
||||||
|
boolean result = firewallMgr.applyRules(network, Purpose.Firewall, rules);
|
||||||
|
|
||||||
|
Assert.assertTrue(result);
|
||||||
|
verify(_vpcMgr, times(1)).isProviderSupportServiceInVpc(10L, Service.Firewall, Network.Provider.VPCVirtualRouter);
|
||||||
|
verify(_networkModel, never()).isProviderSupportServiceInNetwork(Mockito.anyLong(), Mockito.eq(Service.Firewall), Mockito.any());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testApplyRulesForNonVpcNetworkUsesNetworkModelProviderCheck() throws ResourceUnavailableException {
|
||||||
|
FirewallManagerImpl firewallMgr = new FirewallManagerImpl();
|
||||||
|
firewallMgr._networkModel = _networkModel;
|
||||||
|
firewallMgr._vpcMgr = _vpcMgr;
|
||||||
|
|
||||||
|
Network network = Mockito.mock(Network.class);
|
||||||
|
FirewallServiceProvider fwProvider = Mockito.mock(FirewallServiceProvider.class);
|
||||||
|
List<FirewallRule> rules = new ArrayList<>();
|
||||||
|
FirewallRuleVO rule = new FirewallRuleVO("rule1", 1L, 80, 80, "tcp", 1L, 2, 3, Purpose.Firewall,
|
||||||
|
Collections.emptyList(), Collections.emptyList(), null, null, null, FirewallRule.TrafficType.Ingress);
|
||||||
|
rules.add(rule);
|
||||||
|
|
||||||
|
when(network.getId()).thenReturn(1L);
|
||||||
|
when(network.getVpcId()).thenReturn(null);
|
||||||
|
when(fwProvider.getProvider()).thenReturn(Network.Provider.VirtualRouter);
|
||||||
|
when(_networkModel.isProviderSupportServiceInNetwork(1L, Service.Firewall, Network.Provider.VirtualRouter)).thenReturn(true);
|
||||||
|
when(fwProvider.applyFWRules(Mockito.eq(network), Mockito.anyList())).thenReturn(true);
|
||||||
|
firewallMgr._firewallElements = List.of(fwProvider);
|
||||||
|
|
||||||
|
boolean result = firewallMgr.applyRules(network, Purpose.Firewall, rules);
|
||||||
|
|
||||||
|
Assert.assertTrue(result);
|
||||||
|
verify(_networkModel, times(1)).isProviderSupportServiceInNetwork(1L, Service.Firewall, Network.Provider.VirtualRouter);
|
||||||
|
verify(_vpcMgr, never()).isProviderSupportServiceInVpc(Mockito.anyLong(), Mockito.eq(Service.Firewall), Mockito.any());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testGetSourceIpForIngressRuleReturnsNullWhenIdIsNull() {
|
||||||
|
IPAddressVO result = _firewallMgr.getSourceIpForIngressRule(null);
|
||||||
|
Assert.assertNull(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test(expected = CloudRuntimeException.class)
|
||||||
|
public void testGetSourceIpForIngressRuleReturnsNullWhenIpIsnotPresent() {
|
||||||
|
when(_ipAddressDao.findById(1L)).thenReturn(null);
|
||||||
|
_firewallMgr.getSourceIpForIngressRule(1L);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -703,14 +703,139 @@ class CsAcl(CsDataBag):
|
|||||||
self.add_routing_rules()
|
self.add_routing_rules()
|
||||||
return
|
return
|
||||||
|
|
||||||
|
desired_firewall_ips = set()
|
||||||
|
fw_chains_created = set()
|
||||||
|
if self.config.is_vpc() and self.config.is_vpc_firewall_enabled():
|
||||||
|
desired_firewall_ips = self._get_desired_vpc_firewall_ips()
|
||||||
|
# Pre-create FIREWALL chains for ALL public IPs that have any active rule
|
||||||
|
# (static NAT, port forwarding, LB, or explicit firewall rule) so that the
|
||||||
|
# default DROP is always in place even before any explicit firewall rule exists.
|
||||||
|
self._ensure_vpc_firewall_chains(desired_firewall_ips, fw_chains_created)
|
||||||
|
|
||||||
for item in self.dbag:
|
for item in self.dbag:
|
||||||
if item == "id":
|
if item == "id":
|
||||||
continue
|
continue
|
||||||
if self.config.is_vpc():
|
if self.config.is_vpc() and not ("purpose" in self.dbag[item] and self.dbag[item]["purpose"] == "Firewall"):
|
||||||
self.AclDevice(self.dbag[item], self.config).create()
|
self.AclDevice(self.dbag[item], self.config).create()
|
||||||
else:
|
else:
|
||||||
|
if self.config.is_vpc() and self.dbag[item].get("purpose") == "Firewall" and not self.config.is_vpc_firewall_enabled():
|
||||||
|
continue
|
||||||
|
# Chain skeleton is already ensured by the pre-creation pass above;
|
||||||
|
# _ensure_vpc_firewall_chains is idempotent (skips IPs in fw_chains_created).
|
||||||
|
if self.config.is_vpc() and self.config.is_vpc_firewall_enabled() and self.dbag[item].get("purpose") == "Firewall":
|
||||||
|
src_ip = self.dbag[item].get("src_ip")
|
||||||
|
self._ensure_vpc_firewall_chains([src_ip], fw_chains_created)
|
||||||
self.AclIP(self.dbag[item], self.config).create()
|
self.AclIP(self.dbag[item], self.config).create()
|
||||||
|
|
||||||
|
if self.config.is_vpc() and self.config.is_vpc_firewall_enabled():
|
||||||
|
self._cleanup_removed_vpc_firewall_chains(desired_firewall_ips)
|
||||||
|
|
||||||
|
def _get_desired_vpc_firewall_ips(self):
|
||||||
|
"""
|
||||||
|
Collect the full set of public IPs that should have a FIREWALL mangle chain
|
||||||
|
in a VPC with firewall capability. This includes IPs from explicit firewall
|
||||||
|
rules, forwarding/static-NAT rules, and load-balancer rules.
|
||||||
|
"""
|
||||||
|
if not self.config.is_vpc():
|
||||||
|
return set()
|
||||||
|
|
||||||
|
ips = set()
|
||||||
|
ips.update(self._get_firewall_rule_ips())
|
||||||
|
ips.update(self._get_forwarding_rule_ips())
|
||||||
|
ips.update(self._get_loadbalancer_ips())
|
||||||
|
return ips
|
||||||
|
|
||||||
|
def _get_firewall_rule_ips(self):
|
||||||
|
"""Return public IPs that have explicit firewall rules in this data bag."""
|
||||||
|
ips = set()
|
||||||
|
for item in self.dbag:
|
||||||
|
if item == "id":
|
||||||
|
continue
|
||||||
|
rule = self.dbag[item]
|
||||||
|
if rule.get("purpose") == "Firewall":
|
||||||
|
src_ip = rule.get("src_ip")
|
||||||
|
if src_ip:
|
||||||
|
ips.add(src_ip)
|
||||||
|
return ips
|
||||||
|
|
||||||
|
def _get_forwarding_rule_ips(self):
|
||||||
|
"""
|
||||||
|
Return public IPs from the forwardingrules bag (static NAT and port forwarding).
|
||||||
|
That bag is keyed by public IP, so each key (other than 'id') is a public IP.
|
||||||
|
"""
|
||||||
|
ips = set()
|
||||||
|
try:
|
||||||
|
fwd_bag = CsDataBag("forwardingrules", self.config)
|
||||||
|
for public_ip in fwd_bag.get_bag():
|
||||||
|
if public_ip == "id":
|
||||||
|
continue
|
||||||
|
ips.add(public_ip)
|
||||||
|
except Exception as e:
|
||||||
|
logging.debug("Could not load forwardingrules for VPC firewall chain collection: %s", e)
|
||||||
|
return ips
|
||||||
|
|
||||||
|
def _get_loadbalancer_ips(self):
|
||||||
|
"""
|
||||||
|
Return public IPs from the loadbalancer bag.
|
||||||
|
add_rules entries are formatted as 'ip:port', so the IP is the first segment.
|
||||||
|
"""
|
||||||
|
ips = set()
|
||||||
|
try:
|
||||||
|
lb_bag = CsDataBag("loadbalancer", self.config)
|
||||||
|
lb_data = lb_bag.get_bag()
|
||||||
|
if "config" in lb_data and lb_data["config"]:
|
||||||
|
for rule_str in lb_data["config"][0].get("add_rules", []):
|
||||||
|
ip = rule_str.split(":")[0]
|
||||||
|
if ip:
|
||||||
|
ips.add(ip)
|
||||||
|
except Exception as e:
|
||||||
|
logging.debug("Could not load loadbalancer for VPC firewall chain collection: %s", e)
|
||||||
|
return ips
|
||||||
|
|
||||||
|
def _ensure_vpc_firewall_chains(self, source_ips, fw_chains_created):
|
||||||
|
fw = self.config.get_fw()
|
||||||
|
for src_ip in source_ips:
|
||||||
|
if not src_ip or src_ip in fw_chains_created:
|
||||||
|
continue
|
||||||
|
fw.append(["mangle", "front",
|
||||||
|
"-A PREROUTING -d %s/32 -j FIREWALL_%s" % (src_ip, src_ip)])
|
||||||
|
fw.append(["mangle", "front",
|
||||||
|
"-A FIREWALL_%s -m state --state RELATED,ESTABLISHED -j RETURN" % src_ip])
|
||||||
|
fw.append(["mangle", "",
|
||||||
|
"-A FIREWALL_%s -j DROP" % src_ip])
|
||||||
|
fw_chains_created.add(src_ip)
|
||||||
|
|
||||||
|
def _cleanup_removed_vpc_firewall_chains(self, desired_firewall_ips):
|
||||||
|
try:
|
||||||
|
mangle_save = CsHelper.execute("iptables-save -t mangle")
|
||||||
|
existing_firewall_ips = []
|
||||||
|
for line in mangle_save:
|
||||||
|
if line.startswith(":FIREWALL_"):
|
||||||
|
chain = line.split(" ")[0][1:]
|
||||||
|
existing_firewall_ips.append(chain.replace("FIREWALL_", "", 1))
|
||||||
|
|
||||||
|
for src_ip in existing_firewall_ips:
|
||||||
|
if src_ip in desired_firewall_ips:
|
||||||
|
continue
|
||||||
|
self._delete_vpc_firewall_chain(src_ip)
|
||||||
|
except Exception as e:
|
||||||
|
logging.debug("Failed VPC firewall chain cleanup: %s", e)
|
||||||
|
|
||||||
|
def _delete_vpc_firewall_chain(self, src_ip):
|
||||||
|
chain = "FIREWALL_%s" % src_ip
|
||||||
|
try:
|
||||||
|
prerouting_rules = CsHelper.execute("iptables -t mangle -S PREROUTING")
|
||||||
|
for rule in prerouting_rules:
|
||||||
|
if ("-d %s/32" % src_ip) in rule and ("-j %s" % chain) in rule:
|
||||||
|
delete_rule = rule.replace("-A PREROUTING", "-D PREROUTING", 1)
|
||||||
|
CsHelper.execute2("iptables -t mangle %s" % delete_rule, False)
|
||||||
|
|
||||||
|
CsHelper.execute2("iptables -t mangle -F %s" % chain, False)
|
||||||
|
CsHelper.execute2("iptables -t mangle -X %s" % chain, False)
|
||||||
|
logging.info("Deleted VPC firewall chain %s as last firewall rule was removed", chain)
|
||||||
|
except Exception as e:
|
||||||
|
logging.debug("Failed deleting VPC firewall chain %s: %s", chain, e)
|
||||||
|
|
||||||
class CsIpv6Firewall(CsDataBag):
|
class CsIpv6Firewall(CsDataBag):
|
||||||
"""
|
"""
|
||||||
Deal with IPv6 Firewall
|
Deal with IPv6 Firewall
|
||||||
|
|||||||
@ -680,6 +680,7 @@ class CsIP:
|
|||||||
self.fw.append(["filter", "", "-P INPUT DROP"])
|
self.fw.append(["filter", "", "-P INPUT DROP"])
|
||||||
self.fw.append(["filter", "", "-P FORWARD DROP"])
|
self.fw.append(["filter", "", "-P FORWARD DROP"])
|
||||||
|
|
||||||
|
|
||||||
def fw_router_routing(self):
|
def fw_router_routing(self):
|
||||||
if self.config.is_vpc() or not self.config.is_routed():
|
if self.config.is_vpc() or not self.config.is_routed():
|
||||||
return
|
return
|
||||||
|
|||||||
@ -155,3 +155,6 @@ class CsConfig(object):
|
|||||||
|
|
||||||
def has_public_network(self):
|
def has_public_network(self):
|
||||||
return self.cmdline().idata().get('has_public_network', 'true') == 'true'
|
return self.cmdline().idata().get('has_public_network', 'true') == 'true'
|
||||||
|
|
||||||
|
def is_vpc_firewall_enabled(self):
|
||||||
|
return self.cmdline().idata().get('vpc_firewall_enabled', 'false') == 'true'
|
||||||
|
|||||||
187
test/integration/smoke/test_vpc_firewall_rules.py
Normal file
187
test/integration/smoke/test_vpc_firewall_rules.py
Normal file
@ -0,0 +1,187 @@
|
|||||||
|
# Licensed to the Apache Software Foundation (ASF) under one
|
||||||
|
# or more contributor license agreements. See the NOTICE file
|
||||||
|
# distributed with this work for additional information
|
||||||
|
# regarding copyright ownership. The ASF licenses this file
|
||||||
|
# to you under the Apache License, Version 2.0 (the
|
||||||
|
# "License"); you may not use this file except in compliance
|
||||||
|
# with the License. You may obtain a copy of the License at
|
||||||
|
#
|
||||||
|
# http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
#
|
||||||
|
# Unless required by applicable law or agreed to in writing,
|
||||||
|
# software distributed under the License is distributed on an
|
||||||
|
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||||
|
# KIND, either express or implied. See the License for the
|
||||||
|
# specific language governing permissions and limitations
|
||||||
|
# under the License.
|
||||||
|
|
||||||
|
"""Smoke tests for firewall rules on VPC public IPs."""
|
||||||
|
|
||||||
|
from nose.plugins.attrib import attr
|
||||||
|
|
||||||
|
from marvin.cloudstackTestCase import cloudstackTestCase
|
||||||
|
from marvin.lib.base import Account, FireWallRule, Network, NetworkOffering, PublicIPAddress, VPC, VpcOffering
|
||||||
|
from marvin.lib.common import get_domain, get_zone, list_publicIP
|
||||||
|
from marvin.lib.utils import cleanup_resources, wait_until
|
||||||
|
|
||||||
|
|
||||||
|
class TestVpcFirewallRules(cloudstackTestCase):
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def setUpClass(cls):
|
||||||
|
cls.testClient = super(TestVpcFirewallRules, cls).getClsTestClient()
|
||||||
|
cls.apiclient = cls.testClient.getApiClient()
|
||||||
|
cls.services = cls.testClient.getParsedTestDataConfig()
|
||||||
|
cls.zone = get_zone(cls.apiclient, cls.testClient.getZoneForTests())
|
||||||
|
cls.domain = get_domain(cls.apiclient)
|
||||||
|
cls._cleanup = []
|
||||||
|
|
||||||
|
cls.account = Account.create(
|
||||||
|
cls.apiclient,
|
||||||
|
cls.services["account"],
|
||||||
|
domainid=cls.domain.id
|
||||||
|
)
|
||||||
|
cls._cleanup.append(cls.account)
|
||||||
|
|
||||||
|
cls.services["vpc_offering"]["supportedservices"] = (
|
||||||
|
"Vpn,Dhcp,Dns,SourceNat,Lb,UserData,StaticNat,"
|
||||||
|
"NetworkACL,PortForwarding,Firewall"
|
||||||
|
)
|
||||||
|
cls.services["vpc_offering"]["serviceProviderList"] = {
|
||||||
|
"Vpn": "VpcVirtualRouter",
|
||||||
|
"Dhcp": "VpcVirtualRouter",
|
||||||
|
"Dns": "VpcVirtualRouter",
|
||||||
|
"SourceNat": "VpcVirtualRouter",
|
||||||
|
"Lb": "VpcVirtualRouter",
|
||||||
|
"UserData": "VpcVirtualRouter",
|
||||||
|
"StaticNat": "VpcVirtualRouter",
|
||||||
|
"NetworkACL": "VpcVirtualRouter",
|
||||||
|
"PortForwarding": "VpcVirtualRouter",
|
||||||
|
"Firewall": "VpcVirtualRouter"
|
||||||
|
}
|
||||||
|
|
||||||
|
cls.vpc_offering = VpcOffering.create(
|
||||||
|
cls.apiclient,
|
||||||
|
cls.services["vpc_offering"]
|
||||||
|
)
|
||||||
|
cls.vpc_offering.update(cls.apiclient, state="Enabled")
|
||||||
|
cls._cleanup.append(cls.vpc_offering)
|
||||||
|
|
||||||
|
network_offering = NetworkOffering.list(
|
||||||
|
cls.apiclient,
|
||||||
|
name="DefaultIsolatedNetworkOfferingForVpcNetworks"
|
||||||
|
)
|
||||||
|
cls.assertTrue(
|
||||||
|
network_offering is not None and len(network_offering) > 0,
|
||||||
|
"No VPC tier network offering found"
|
||||||
|
)
|
||||||
|
cls.network_offering = network_offering[0]
|
||||||
|
cls.services["vpc"]["cidr"] = "10.20.30.0/24"
|
||||||
|
cls.vpc = VPC.create(
|
||||||
|
cls.apiclient,
|
||||||
|
cls.services["vpc"],
|
||||||
|
vpcofferingid=cls.vpc_offering.id,
|
||||||
|
zoneid=cls.zone.id,
|
||||||
|
account=cls.account.name,
|
||||||
|
domainid=cls.account.domainid
|
||||||
|
)
|
||||||
|
|
||||||
|
cls.tier = Network.create(
|
||||||
|
cls.apiclient,
|
||||||
|
services={
|
||||||
|
"name": "vpc-fw-tier",
|
||||||
|
"displaytext": "vpc-fw-tier"
|
||||||
|
},
|
||||||
|
accountid=cls.account.name,
|
||||||
|
domainid=cls.account.domainid,
|
||||||
|
networkofferingid=cls.network_offering.id,
|
||||||
|
zoneid=cls.zone.id,
|
||||||
|
vpcid=cls.vpc.id,
|
||||||
|
gateway="10.20.30.1",
|
||||||
|
netmask="255.255.255.0"
|
||||||
|
)
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def tearDownClass(cls):
|
||||||
|
try:
|
||||||
|
cleanup_resources(cls.apiclient, cls._cleanup)
|
||||||
|
except Exception as e:
|
||||||
|
raise Exception("Warning: Exception during cleanup: %s" % e)
|
||||||
|
|
||||||
|
def setUp(self):
|
||||||
|
self.apiclient = self.testClient.getApiClient()
|
||||||
|
self.cleanup = []
|
||||||
|
|
||||||
|
def tearDown(self):
|
||||||
|
cleanup_resources(self.apiclient, self.cleanup)
|
||||||
|
|
||||||
|
def _wait_for_firewall_rule(self, rule_id):
|
||||||
|
rules = FireWallRule.list(self.apiclient, id=rule_id, listall=True)
|
||||||
|
if rules and len(rules) == 1:
|
||||||
|
return True, rules[0]
|
||||||
|
return False, None
|
||||||
|
|
||||||
|
@attr(tags=["advanced", "advancedns", "smoke"], required_hardware="false")
|
||||||
|
def test_01_create_firewall_rule_on_vpc_public_ip(self):
|
||||||
|
"""Verify firewall rule can be created and listed on a dedicated VPC public IP."""
|
||||||
|
public_ip = PublicIPAddress.create(
|
||||||
|
self.apiclient,
|
||||||
|
zoneid=self.zone.id,
|
||||||
|
accountid=self.account.name,
|
||||||
|
domainid=self.account.domainid,
|
||||||
|
vpcid=self.vpc.id
|
||||||
|
)
|
||||||
|
self.cleanup.append(public_ip)
|
||||||
|
|
||||||
|
firewall_rule = FireWallRule.create(
|
||||||
|
self.apiclient,
|
||||||
|
ipaddressid=public_ip.ipaddress.id,
|
||||||
|
protocol="tcp",
|
||||||
|
cidrlist=["0.0.0.0/0"],
|
||||||
|
startport=19090,
|
||||||
|
endport=19090,
|
||||||
|
vpcid=self.vpc.id
|
||||||
|
)
|
||||||
|
self.cleanup.insert(0, firewall_rule)
|
||||||
|
|
||||||
|
result, listed_rule = wait_until(2, 10, self._wait_for_firewall_rule, firewall_rule.id)
|
||||||
|
self.assertTrue(result, "Firewall rule was not listed for the VPC public IP")
|
||||||
|
self.assertEqual(listed_rule.id, firewall_rule.id)
|
||||||
|
self.assertEqual(listed_rule.ipaddressid, public_ip.ipaddress.id)
|
||||||
|
self.assertEqual(listed_rule.vpcid, self.vpc.id)
|
||||||
|
self.assertEqual(listed_rule.protocol.lower(), "tcp")
|
||||||
|
self.assertEqual(int(listed_rule.startport), 19090)
|
||||||
|
self.assertEqual(int(listed_rule.endport), 19090)
|
||||||
|
|
||||||
|
@attr(tags=["advanced", "advancedns", "smoke"], required_hardware="false")
|
||||||
|
def test_02_create_firewall_rule_on_vpc_source_nat_ip(self):
|
||||||
|
"""Verify firewall rule can be created and listed on the VPC source NAT IP."""
|
||||||
|
source_nat_ips = list_publicIP(
|
||||||
|
self.apiclient,
|
||||||
|
vpcid=self.vpc.id,
|
||||||
|
listall=True,
|
||||||
|
issourcenat=True
|
||||||
|
)
|
||||||
|
self.assertTrue(source_nat_ips is not None and len(source_nat_ips) > 0,
|
||||||
|
"No source NAT IP found for the VPC")
|
||||||
|
source_nat_ip = source_nat_ips[0]
|
||||||
|
|
||||||
|
firewall_rule = FireWallRule.create(
|
||||||
|
self.apiclient,
|
||||||
|
ipaddressid=source_nat_ip.id,
|
||||||
|
protocol="tcp",
|
||||||
|
cidrlist=["0.0.0.0/0"],
|
||||||
|
startport=19443,
|
||||||
|
endport=19443,
|
||||||
|
vpcid=self.vpc.id
|
||||||
|
)
|
||||||
|
self.cleanup.append(firewall_rule)
|
||||||
|
|
||||||
|
result, listed_rule = wait_until(2, 10, self._wait_for_firewall_rule, firewall_rule.id)
|
||||||
|
self.assertTrue(result, "Firewall rule was not listed for the VPC source NAT IP")
|
||||||
|
self.assertEqual(listed_rule.id, firewall_rule.id)
|
||||||
|
self.assertEqual(listed_rule.ipaddressid, source_nat_ip.id)
|
||||||
|
self.assertEqual(listed_rule.vpcid, self.vpc.id)
|
||||||
|
self.assertEqual(listed_rule.protocol.lower(), "tcp")
|
||||||
|
self.assertEqual(int(listed_rule.startport), 19443)
|
||||||
|
self.assertEqual(int(listed_rule.endport), 19443)
|
||||||
@ -136,23 +136,39 @@ export default {
|
|||||||
}
|
}
|
||||||
if (this.resource && this.resource.vpcid) {
|
if (this.resource && this.resource.vpcid) {
|
||||||
const vpc = await this.fetchVpc()
|
const vpc = await this.fetchVpc()
|
||||||
|
const hasFirewallCapability = this.hasVpcFirewallCapability(vpc)
|
||||||
|
|
||||||
// VPC IPs with source nat have only VPN when VPC offering conserve mode = false
|
// VPC IPs with source nat have only VPN when VPC offering conserve mode = false
|
||||||
if (this.resource.issourcenat && vpc?.vpcofferingconservemode === false) {
|
if (this.resource.issourcenat && vpc?.vpcofferingconservemode === false) {
|
||||||
this.tabs = this.defaultTabs.concat(this.$route.meta.tabs.filter(tab => tab.name === 'vpn'))
|
const tabs = this.defaultTabs.concat(this.$route.meta.tabs.filter(tab => tab.name === 'vpn'))
|
||||||
|
this.tabs = hasFirewallCapability ? this.addFirewallTab(tabs) : tabs
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// VPC IPs with static nat have nothing
|
// VPC IPs with static nat keep existing VPN behavior; show firewall only when capability exists
|
||||||
if (this.resource.isstaticnat) {
|
if (this.resource.isstaticnat) {
|
||||||
if (this.resource.virtualmachinetype === 'DomainRouter') {
|
let tabs = this.$route.meta.tabs
|
||||||
this.tabs = this.defaultTabs.concat(this.$route.meta.tabs.filter(tab => tab.name === 'vpn'))
|
if (hasFirewallCapability) {
|
||||||
|
tabs = this.addFirewallTab(tabs).map(tab => {
|
||||||
|
if (tab.name !== 'firewall') {
|
||||||
|
return tab
|
||||||
|
}
|
||||||
|
const staticNatFirewallTab = { ...tab }
|
||||||
|
delete staticNatFirewallTab.networkServiceFilter
|
||||||
|
return staticNatFirewallTab
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
tabs = tabs.filter(tab => tab.name !== 'firewall')
|
||||||
}
|
}
|
||||||
|
this.tabs = tabs
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// VPC IPs don't have firewall
|
// VPC IPs have all tabs; firewall is shown only if VPC has firewall capability
|
||||||
let tabs = this.$route.meta.tabs.filter(tab => tab.name !== 'firewall')
|
let tabs = this.$route.meta.tabs
|
||||||
|
if (!hasFirewallCapability) {
|
||||||
|
tabs = tabs.filter(tab => tab.name !== 'firewall')
|
||||||
|
}
|
||||||
|
|
||||||
const network = await this.fetchNetwork()
|
const network = await this.fetchNetwork()
|
||||||
if (network && network.networkofferingconservemode) {
|
if (network && network.networkofferingconservemode) {
|
||||||
@ -168,12 +184,12 @@ export default {
|
|||||||
this.portFWRuleCount = await this.fetchPortFWRule()
|
this.portFWRuleCount = await this.fetchPortFWRule()
|
||||||
this.loadBalancerRuleCount = await this.fetchLoadBalancerRule()
|
this.loadBalancerRuleCount = await this.fetchLoadBalancerRule()
|
||||||
|
|
||||||
// VPC IPs with PF only have PF
|
// VPC IPs with PF only have PF (and firewall)
|
||||||
if (this.portFWRuleCount > 0) {
|
if (this.portFWRuleCount > 0) {
|
||||||
tabs = tabs.filter(tab => tab.name !== 'loadbalancing')
|
tabs = tabs.filter(tab => tab.name !== 'loadbalancing')
|
||||||
}
|
}
|
||||||
|
|
||||||
// VPC IPs with LB rules only have LB
|
// VPC IPs with LB rules only have LB (and firewall)
|
||||||
if (this.loadBalancerRuleCount > 0) {
|
if (this.loadBalancerRuleCount > 0) {
|
||||||
tabs = tabs.filter(tab => tab.name !== 'portforwarding')
|
tabs = tabs.filter(tab => tab.name !== 'portforwarding')
|
||||||
}
|
}
|
||||||
@ -200,6 +216,17 @@ export default {
|
|||||||
fetchAction () {
|
fetchAction () {
|
||||||
this.actions = this.$route.meta.actions || []
|
this.actions = this.$route.meta.actions || []
|
||||||
},
|
},
|
||||||
|
addFirewallTab (tabs) {
|
||||||
|
const firewallTab = this.$route.meta.tabs.find(tab => tab.name === 'firewall')
|
||||||
|
if (!firewallTab || tabs.some(tab => tab.name === 'firewall')) {
|
||||||
|
return tabs
|
||||||
|
}
|
||||||
|
return tabs.concat(firewallTab)
|
||||||
|
},
|
||||||
|
hasVpcFirewallCapability (vpc) {
|
||||||
|
const services = vpc?.service || []
|
||||||
|
return Array.isArray(services) && services.some(service => (service?.name || '').toLowerCase() === 'firewall')
|
||||||
|
},
|
||||||
fetchVpc () {
|
fetchVpc () {
|
||||||
if (!this.resource.vpcid) {
|
if (!this.resource.vpcid) {
|
||||||
return null
|
return null
|
||||||
|
|||||||
@ -946,6 +946,9 @@ export default {
|
|||||||
provider.enabled = self.isVpcCoreProvider(provider.name, svc.name) ||
|
provider.enabled = self.isVpcCoreProvider(provider.name, svc.name) ||
|
||||||
!self.isBuiltInNetworkProvider(provider.name)
|
!self.isBuiltInNetworkProvider(provider.name)
|
||||||
}
|
}
|
||||||
|
if (svc.name === 'Firewall' && provider.name === 'VpcVirtualRouter') {
|
||||||
|
provider.enabled = false
|
||||||
|
}
|
||||||
} else { // *** non-vpc ***
|
} else { // *** non-vpc ***
|
||||||
provider.enabled = !['InternalLbVm', 'VpcVirtualRouter', 'Nsx', 'Netris'].includes(provider.name)
|
provider.enabled = !['InternalLbVm', 'VpcVirtualRouter', 'Nsx', 'Netris'].includes(provider.name)
|
||||||
}
|
}
|
||||||
|
|||||||
@ -432,6 +432,9 @@ export default {
|
|||||||
})
|
})
|
||||||
},
|
},
|
||||||
isVpcCoreProvider (providerName, serviceName) {
|
isVpcCoreProvider (providerName, serviceName) {
|
||||||
|
if (serviceName === 'Firewall') {
|
||||||
|
return ['VpcVirtualRouter'].includes(providerName)
|
||||||
|
}
|
||||||
if (['VpcVirtualRouter', 'Netscaler', 'BigSwitchBcf', 'ConfigDrive'].includes(providerName)) {
|
if (['VpcVirtualRouter', 'Netscaler', 'BigSwitchBcf', 'ConfigDrive'].includes(providerName)) {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
@ -540,7 +543,7 @@ export default {
|
|||||||
this.supportedServices = []
|
this.supportedServices = []
|
||||||
this.supportedServiceLoading = true
|
this.supportedServiceLoading = true
|
||||||
getAPI('listSupportedNetworkServices').then(json => {
|
getAPI('listSupportedNetworkServices').then(json => {
|
||||||
const vpcServices = ['Dhcp', 'Dns', 'Lb', 'Gateway', 'StaticNat', 'SourceNat', 'NetworkACL', 'PortForwarding', 'UserData', 'Vpn', 'Connectivity', 'CustomAction']
|
const vpcServices = ['Dhcp', 'Dns', 'Lb', 'Gateway', 'StaticNat', 'SourceNat', 'NetworkACL', 'PortForwarding', 'UserData', 'Vpn', 'Connectivity', 'CustomAction', 'Firewall']
|
||||||
services = (json?.listsupportednetworkservicesresponse?.networkservice || [])
|
services = (json?.listsupportednetworkservicesresponse?.networkservice || [])
|
||||||
.filter(service => vpcServices.includes(service.name))
|
.filter(service => vpcServices.includes(service.name))
|
||||||
.map(service => {
|
.map(service => {
|
||||||
@ -575,7 +578,7 @@ export default {
|
|||||||
|
|
||||||
this.supportedServices = []
|
this.supportedServices = []
|
||||||
if (this.networkmode === 'ROUTED') {
|
if (this.networkmode === 'ROUTED') {
|
||||||
services = services.filter(service => !['SourceNat', 'StaticNat', 'Lb', 'PortForwarding', 'Vpn'].includes(service.name))
|
services = services.filter(service => !['SourceNat', 'StaticNat', 'Lb', 'PortForwarding', 'Vpn', 'Firewall'].includes(service.name))
|
||||||
}
|
}
|
||||||
this.supportedServices = services
|
this.supportedServices = services
|
||||||
}).catch(error => {
|
}).catch(error => {
|
||||||
|
|||||||
@ -523,6 +523,7 @@ export default {
|
|||||||
return [
|
return [
|
||||||
{ name: 'Dhcp', provider: [{ name: 'VpcVirtualRouter' }, { name: 'ConfigDrive' }] },
|
{ name: 'Dhcp', provider: [{ name: 'VpcVirtualRouter' }, { name: 'ConfigDrive' }] },
|
||||||
{ name: 'Dns', provider: [{ name: 'VpcVirtualRouter' }, { name: 'ConfigDrive' }] },
|
{ name: 'Dns', provider: [{ name: 'VpcVirtualRouter' }, { name: 'ConfigDrive' }] },
|
||||||
|
{ name: 'Firewall', provider: [{ name: 'VpcVirtualRouter' }] },
|
||||||
{ name: 'Lb', provider: [{ name: 'VpcVirtualRouter' }, { name: 'InternalLbVm' }] },
|
{ name: 'Lb', provider: [{ name: 'VpcVirtualRouter' }, { name: 'InternalLbVm' }] },
|
||||||
{ name: 'Gateway', provider: [{ name: 'VpcVirtualRouter' }, { name: 'BigSwitchBcf' }] },
|
{ name: 'Gateway', provider: [{ name: 'VpcVirtualRouter' }, { name: 'BigSwitchBcf' }] },
|
||||||
{ name: 'StaticNat', provider: [{ name: 'VpcVirtualRouter' }, { name: 'BigSwitchBcf' }] },
|
{ name: 'StaticNat', provider: [{ name: 'VpcVirtualRouter' }, { name: 'BigSwitchBcf' }] },
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user