Skip to content

Commit

Permalink
feat/policy-names: Add network policy names in hubble UI when they ar…
Browse files Browse the repository at this point in the history
…e known and correlated to flows.

Fixes: cilium/hubble#1100
Signed-off-by: Kris Gambirazzi <kris.gambirazzi@transferwise.com>
  • Loading branch information
kgtw committed Nov 26, 2023
1 parent 05eebce commit fd2c4ce
Show file tree
Hide file tree
Showing 12 changed files with 223 additions and 88 deletions.
2 changes: 2 additions & 0 deletions src/api/__mocks__/data.ts
Original file line number Diff line number Diff line change
Expand Up @@ -372,5 +372,7 @@ export const flows: HubbleFlow[] = range(1000).map((): HubbleFlow => {
trafficDirection:
Math.random() <= 0.5 ? TrafficDirection.Egress : TrafficDirection.Ingress,
authType: AuthType.Disbaled,
egressAllowedBy: [],
ingressAllowedBy: [],
};
});
4 changes: 2 additions & 2 deletions src/api/grpc/common.ts
Original file line number Diff line number Diff line change
Expand Up @@ -181,8 +181,8 @@ export const filterEntryWhitelistFilters = (
const pod = filter.podNamespace
? `${filter.podNamespace}/${filter.query}`
: filters.namespace
? `${filters.namespace}/${filter.query}`
: null;
? `${filters.namespace}/${filter.query}`
: null;

if (filter.fromRequired) {
// NOTE: this makes possible to catch flows [outside of ns] -> [ns]
Expand Down
18 changes: 18 additions & 0 deletions src/components/FlowsTable/Sidebar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ import {
DnsBodyItem,
IdentityEntry,
PodEntry,
PolicyEntry,
} from './SidebarComponents';

import css from './styles.scss';
Expand Down Expand Up @@ -460,6 +461,23 @@ export const FlowsTableSidebar = memo<Props>(function FlowsTableSidebar(props) {
</div>
</section>
)}
<hr />
{flow.hasEgressAllowedBy && (
<section className={css.block}>
<span className={css.title}>Egress allowed by policies</span>
<div className={css.body}>
<PolicyEntry allowedBy={flow.egressAllowedBy} />
</div>
</section>
)}
{flow.hasIngressAllowedBy && (
<section className={css.block}>
<span className={css.title}>Ingress allowed by policies</span>
<div className={css.body}>
<PolicyEntry allowedBy={flow.ingressAllowedBy} />
</div>
</section>
)}
</div>
);
});
26 changes: 26 additions & 0 deletions src/components/FlowsTable/SidebarComponents.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -252,3 +252,29 @@ export const PodEntry = memo<PodItemProps>(
);
},
);

export interface PolicyEntryProps {
allowedBy: string[];
}

export const PolicyEntry = memo<PolicyEntryProps>(
function FlowsTableSidebarLabelsEntry(props) {
return (
<div className={css.policies}>
{props.allowedBy.map(policyName => {
return <PolicyEntryItem key={policyName} name={policyName} />;
})}
</div>
);
},
);

export interface PolicyEntryItemProps {
name: string;
}

export const PolicyEntryItem = memo<PolicyEntryItemProps>(
function FlowsTableSidebarPolicyEntry(props) {
return <span className={css.policy}>{props.name}</span>;
},
);
6 changes: 6 additions & 0 deletions src/components/FlowsTable/styles.scss
Original file line number Diff line number Diff line change
Expand Up @@ -237,6 +237,12 @@
}
}

.policies {
.policy {
display: block;
}
}

.tcpFlags {
.tcpFlag {
margin-right: 5px;
Expand Down
4 changes: 2 additions & 2 deletions src/components/TopBar/NamespaceSelectorDropdown.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -58,8 +58,8 @@ export const NamespaceSelectorDropdown = memo<Props>(
currentNamespace && namespaces.includes(currentNamespace)
? currentNamespace
: currentNamespace
? `Waiting ${currentNamespace} namespace…`
: 'Choose namespace';
? `Waiting ${currentNamespace} namespace…`
: 'Choose namespace';

return (
<NamespaceSelect
Expand Down
20 changes: 18 additions & 2 deletions src/domain/flows/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -333,8 +333,8 @@ export class Flow {
this.l7?.type === L7FlowType.Request
? '->'
: this.l7?.type === L7FlowType.Response
? '<-'
: '??';
? '<-'
: '??';

// TODO: check if this is a correct fingerprints for all but http
return `${direction} ${l7helpers.getEndpointId(l7)}`;
Expand Down Expand Up @@ -517,4 +517,20 @@ export class Flow {
public get authTypeLabel(): string {
return authtypeHelpers.toString(this.ref.authType);
}

public get hasEgressAllowedBy(): boolean {
return this.ref.egressAllowedBy.length > 0;
}

public get hasIngressAllowedBy(): boolean {
return this.ref.ingressAllowedBy.length > 0;
}

public get egressAllowedBy(): string[] {
return this.ref.egressAllowedBy || [];
}

public get ingressAllowedBy(): string[] {
return this.ref.ingressAllowedBy || [];
}
}
35 changes: 35 additions & 0 deletions src/domain/helpers/flows.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import {
TrafficDirection as PBTrafficDirection,
CiliumEventType as PBCiliumEventType,
Service as PBService,
Policy as Policy,
} from '~backend/proto/flow/flow_pb';

import {
Expand Down Expand Up @@ -47,6 +48,8 @@ import * as misc from '~/domain/misc';
import * as verdictHelpers from './verdict';
import { authTypeFromPb } from './auth-type';

const derivedFrom = 'reserved:io.cilium.policy.derived-from';

export const hubbleFlowFromObj = (obj: any): HubbleFlow | null => {
obj = obj.flow != null ? obj.flow : obj;

Expand Down Expand Up @@ -84,6 +87,9 @@ export const hubbleFlowFromObj = (obj: any): HubbleFlow | null => {
const trafficDirection = trafficDirectionFromStr(obj.trafficDirection);
const authType = authTypeFromStr(obj.authType);

const egressAllowedBy = getNameFromPolicy(obj.getEgressAllowedByList);
const ingressAllowedBy = getNameFromPolicy(obj.getIngressAllowedByList);

return {
time,
verdict,
Expand All @@ -105,6 +111,8 @@ export const hubbleFlowFromObj = (obj: any): HubbleFlow | null => {
summary: obj.summary,
trafficDirection,
authType,
egressAllowedBy,
ingressAllowedBy,
};
};

Expand Down Expand Up @@ -148,6 +156,9 @@ export const hubbleFlowFromPb = (flow: PBFlow): HubbleFlow => {
const trafficDirection = trafficDirectionFromPb(flow.getTrafficDirection());
const authType = authTypeFromPb(flow.getAuthType());

const egressAllowedBy = getNameFromPolicy(flow.getEgressAllowedByList());
const ingressAllowedBy = getNameFromPolicy(flow.getIngressAllowedByList());

return {
time,
verdict,
Expand All @@ -169,6 +180,8 @@ export const hubbleFlowFromPb = (flow: PBFlow): HubbleFlow => {
summary: flow.getSummary(),
trafficDirection,
authType,
egressAllowedBy: egressAllowedBy,
ingressAllowedBy: ingressAllowedBy,
};
};

Expand Down Expand Up @@ -512,3 +525,25 @@ export const icmpv4FromPb = (icmp: PBICMPv4): ICMPv4 => {
export const icmpv6FromPb = (icmp: PBICMPv6): ICMPv6 => {
return icmpv4FromPb(icmp);
};

export const getNameFromPolicy = (policies: Array<Policy>): Array<string> => {
return policies.map(policy => {
if (policy.getName() === '') {
const labelMap = new Map<string, string>();
policy.getLabelsList().forEach(keyValueString => {
const [key, value] = keyValueString.split('=');
labelMap.set(key, value);
});

// Note: We try to automatically derive the policy name if it is set.
// This is set by the policy mapstate for certain known scenarios, like allowing localhost access.
// See: https://github.com/cilium/cilium/blob/614f2ddcc8fe93aeaf463b4535dcc0f1dcc373a3/pkg/policy/mapstate.go#L42-L49
if (labelMap.has(derivedFrom)) {
return '<cilium-internal>/' + labelMap.get(derivedFrom);
}
return '<cilium-internal>/unknown';
}

return policy.getNamespace() + '/' + policy.getName();
});
};
2 changes: 2 additions & 0 deletions src/domain/hubble.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@ export interface HubbleFlow {
readonly summary: string;
readonly trafficDirection: TrafficDirection;
readonly authType: AuthType;
readonly egressAllowedBy: Array<string>;
readonly ingressAllowedBy: Array<string>;
}

export interface HubbleService {
Expand Down
4 changes: 4 additions & 0 deletions src/testing/data/flows.ts
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,8 @@ export const icmpv4Flow: HubbleFlow = {
},
trafficDirection: TrafficDirection.Ingress,
authType: AuthType.Disbaled,
egressAllowedBy: [],
ingressAllowedBy: [],
};

export const icmpv6Flow: HubbleFlow = {
Expand Down Expand Up @@ -96,6 +98,8 @@ export const hubbleOne: HubbleFlow = {
},
trafficDirection: TrafficDirection.Ingress,
authType: AuthType.Disbaled,
egressAllowedBy: [],
ingressAllowedBy: [],
};

export const hubbleNoSourceName: HubbleFlow = {
Expand Down
12 changes: 12 additions & 0 deletions src/testing/helpers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,8 @@ export const flowsBetweenPods = (
time: nextFlowTimestamp(),
trafficDirection: TrafficDirection.Ingress,
authType: AuthType.Disbaled,
egressAllowedBy: [],
ingressAllowedBy: [],
};

const fromBtoA: HubbleFlow = {
Expand Down Expand Up @@ -98,6 +100,8 @@ export const flowsBetweenPods = (
time: nextFlowTimestamp(),
trafficDirection: TrafficDirection.Ingress,
authType: AuthType.Disbaled,
egressAllowedBy: [],
ingressAllowedBy: [],
};

return { fromAtoB, fromBtoA };
Expand Down Expand Up @@ -139,6 +143,8 @@ export const flowsBetweenServices = (
time: nextFlowTimestamp(),
trafficDirection: TrafficDirection.Ingress,
authType: AuthType.Disbaled,
egressAllowedBy: [],
ingressAllowedBy: [],
};

const fromBtoA: HubbleFlow = {
Expand Down Expand Up @@ -173,6 +179,8 @@ export const flowsBetweenServices = (
time: nextFlowTimestamp(),
trafficDirection: TrafficDirection.Ingress,
authType: AuthType.Disbaled,
egressAllowedBy: [],
ingressAllowedBy: [],
};

return { fromAtoB, fromBtoA };
Expand Down Expand Up @@ -221,6 +229,8 @@ export const flowsFromToService = (from: HubbleService, to: HubbleService) => {
time: nextFlowTimestamp(),
trafficDirection: TrafficDirection.Ingress,
authType: AuthType.Disbaled,
egressAllowedBy: [],
ingressAllowedBy: [],
};

const fromBtoA: HubbleFlow = {
Expand Down Expand Up @@ -253,6 +263,8 @@ export const flowsFromToService = (from: HubbleService, to: HubbleService) => {
time: nextFlowTimestamp(),
trafficDirection: TrafficDirection.Ingress,
authType: AuthType.Disbaled,
egressAllowedBy: [],
ingressAllowedBy: [],
};

return { fromAtoB, fromBtoA };
Expand Down

0 comments on commit fd2c4ce

Please sign in to comment.