packages/@aws-cdk/cloudformation-diff/lib/network/security-group-rule.ts (118 lines of code) (raw):
/**
* A single security group rule, either egress or ingress
*/
export class SecurityGroupRule {
/**
* Group ID of the group this rule applies to
*/
public readonly groupId: string;
/**
* IP protocol this rule applies to
*/
public readonly ipProtocol: string;
/**
* Start of port range this rule applies to, or ICMP type
*/
public readonly fromPort?: number;
/**
* End of port range this rule applies to, or ICMP code
*/
public readonly toPort?: number;
/**
* Peer of this rule
*/
public readonly peer?: RulePeer;
constructor(ruleObject: any, groupRef?: string) {
this.ipProtocol = ruleObject.IpProtocol?.toString() || '*unknown*';
this.fromPort = ruleObject.FromPort;
this.toPort = ruleObject.ToPort;
this.groupId = ruleObject.GroupId || groupRef || '*unknown*'; // In case of an inline rule
this.peer =
findFirst(ruleObject,
['CidrIp', 'CidrIpv6'],
(ip) => ({ kind: 'cidr-ip', ip } as CidrIpPeer))
||
findFirst(ruleObject,
['DestinationSecurityGroupId', 'SourceSecurityGroupId'],
(securityGroupId) => ({ kind: 'security-group', securityGroupId } as SecurityGroupPeer))
||
findFirst(ruleObject,
['DestinationPrefixListId', 'SourcePrefixListId'],
(prefixListId) => ({ kind: 'prefix-list', prefixListId } as PrefixListPeer));
}
public equal(other: SecurityGroupRule) {
return this.ipProtocol === other.ipProtocol
&& this.fromPort === other.fromPort
&& this.toPort === other.toPort
&& peerEqual(this.peer, other.peer);
}
public describeProtocol() {
if (this.ipProtocol === '-1') {
return 'Everything';
}
const ipProtocol = this.ipProtocol.toUpperCase();
if (this.fromPort === -1) {
return `All ${ipProtocol}`;
}
if (this.fromPort === this.toPort) {
return `${ipProtocol} ${this.fromPort}`;
}
return `${ipProtocol} ${this.fromPort}-${this.toPort}`;
}
public describePeer() {
if (this.peer) {
switch (this.peer.kind) {
case 'cidr-ip':
if (this.peer.ip === '0.0.0.0/0') {
return 'Everyone (IPv4)';
}
if (this.peer.ip === '::/0') {
return 'Everyone (IPv6)';
}
return `${this.peer.ip}`;
case 'prefix-list': return `${this.peer.prefixListId}`;
case 'security-group': return `${this.peer.securityGroupId}`;
}
}
return '?';
}
public toJson(): RuleJson {
return {
groupId: this.groupId,
ipProtocol: this.ipProtocol,
fromPort: this.fromPort,
toPort: this.toPort,
peer: this.peer,
};
}
}
export interface CidrIpPeer {
kind: 'cidr-ip';
ip: string;
}
export interface SecurityGroupPeer {
kind: 'security-group';
securityGroupId: string;
}
export interface PrefixListPeer {
kind: 'prefix-list';
prefixListId: string;
}
export type RulePeer = CidrIpPeer | SecurityGroupPeer | PrefixListPeer;
function peerEqual(a?: RulePeer, b?: RulePeer) {
if ((a === undefined) !== (b === undefined)) {
return false;
}
if (a === undefined) {
return true;
}
if (a.kind !== b!.kind) {
return false;
}
switch (a.kind) {
case 'cidr-ip': return a.ip === (b as typeof a).ip;
case 'security-group': return a.securityGroupId === (b as typeof a).securityGroupId;
case 'prefix-list': return a.prefixListId === (b as typeof a).prefixListId;
}
}
function findFirst<T>(obj: any, keys: string[], fn: (x: string) => T): T | undefined {
for (const key of keys) {
try {
if (key in obj) {
return fn(obj[key]);
}
} catch (e) {
debugger;
}
}
return undefined;
}
export interface RuleJson {
groupId: string;
ipProtocol: string;
fromPort?: number;
toPort?: number;
peer?: RulePeer;
}