Skip to content

Commit

Permalink
Merge pull request #10 from CrowdStrike/proxy-requests
Browse files Browse the repository at this point in the history
Proxy requests
  • Loading branch information
evanstoner authored Oct 25, 2024
2 parents b871ba5 + 1eadf7a commit 369e605
Show file tree
Hide file tree
Showing 7 changed files with 80 additions and 15 deletions.
3 changes: 3 additions & 0 deletions .prettierignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# avoid issues with bracket spacing around e.g. {{ .Release.Namespace }}
# https://github.com/redhat-developer/vscode-yaml/issues/246
charts/openshift-console-plugin/templates/*.yaml
14 changes: 6 additions & 8 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
[![Docker Repository on Quay](https://quay.io/repository/crowdstrike/falcon-openshift-console-plugin/status 'Docker Repository on Quay')](https://quay.io/repository/crowdstrike/falcon-openshift-console-plugin)

This is a dynamic plugin for the Red Hat OpenShift console. The plugin provides additional visibility
to the Falcon operator and Falcon-protected virtual machines.
to the Falcon operator and Falcon-protected virtual machines and pods.

### Extension to the VirtualMachine page

Expand All @@ -30,12 +30,9 @@ The Falcon OpenShift Console Plugin is available at [quay.io/crowdstrike/falcon-
Install the chart using the name of the plugin as the Helm release name into a new namespace or an existing namespace as specified by the `plugin_console-plugin-template` parameter by using the following command:

```shell
helm upgrade -i my-plugin charts/openshift-console-plugin -n plugin__console-plugin-template --create-namespace --set plugin.image=quay.io/crowdstrike/falcon-openshift-console-plugin:latest
helm upgrade -i falcon-openshift-console-plugin charts/openshift-console-plugin -n falcon-openshift-console-plugin --create-namespace --set plugin.image=quay.io/crowdstrike/falcon-openshift-console-plugin:latest
```

> [!NOTE]
> When deploying on OpenShift 4.10, it is recommended to add the parameter `--set plugin.securityContext.enabled=false` which will omit configurations related to Pod Security.
> [!NOTE]
> When defining i18n namespace, adhere `plugin__<name-of-the-plugin>` format. The name of the plugin should be extracted from the `consolePlugin` declaration within the [package.json](package.json) file.
Expand All @@ -46,19 +43,20 @@ helm upgrade -i my-plugin charts/openshift-console-plugin -n plugin__console-pl
- Alerts: Read
- Hosts: Read
- Vulnerabilities: Read
- Falcon Container Image: Read

2. In the same namespace as virtual machine workloads, create a secret named `crowdstrike-api` with
2. In the same namespace as virtual machine or pod workloads where you want security visibility, create a secret named `crowdstrike-api` with
the following fields:

- `cloud` (e.g. `us-1`)
- `client_id`
- `client_secret`

> [!NOTE]
> This configuration assumes any user with access to read secrets in the chosen namespace should
> have access to the API client itself, as well as the related data from the Falcon platform.
If you have multiple namespaces with VM workloads, you will need to configure a `crowdstrike-api` secret
in each.
If you have multiple namespaces where you want to surface CrowdStrike security data, you will need to configure a `crowdstrike-api` secret in each.

## Development

Expand Down
28 changes: 28 additions & 0 deletions charts/openshift-console-plugin/templates/configmap.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -14,11 +14,39 @@ data:
include /etc/nginx/mime.types;
default_type application/octet-stream;
keepalive_timeout 65;
upstream crowdstrike_us1 {
server api.crowdstrike.com:443;
}
upstream crowdstrike_us2 {
server api.us-2.crowdstrike.com:443;
}
upstream crowdstrike_eu1 {
server api.eu-1.crowdstrike.com:443;
}
# we receive the region in the header thanks to ProxiedFetch, so map that to the right upstream
map $http_x_cs_region $api_upstream {
default crowdstrike_us1;
us-1 crowdstrike_us1;
us-2 crowdstrike_us2;
eu-1 crowdstrike_eu1;
}
server {
listen {{ .Values.plugin.port }} ssl;
listen [::]:{{ .Values.plugin.port }} ssl;
ssl_certificate /var/cert/tls.crt;
ssl_certificate_key /var/cert/tls.key;
root /usr/share/nginx/html;
location /crwdapi/ {
# a rewrite is not usually needed with a location like /foo/ and with a trailing slash on
# proxy_pass, but variables mess with this behavior https://stackoverflow.com/a/71224059
rewrite ^/crwdapi/(.*) /$1 break;
proxy_pass https://$api_upstream;
}
}
}
16 changes: 14 additions & 2 deletions charts/openshift-console-plugin/templates/consoleplugin.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,24 @@ metadata:
{{- include "openshift-console-plugin.labels" . | nindent 4 }}
spec:
displayName: {{ default (printf "%s Plugin" (include "openshift-console-plugin.name" .)) .Values.plugin.description }}
i18n:
i18n:
loadType: Preload
backend:
type: Service
service:
name: {{ template "openshift-console-plugin.name" . }}
namespace: {{ .Release.Namespace }}
port: {{ .Values.plugin.port }}
basePath: {{ .Values.plugin.basePath }}
basePath: {{ .Values.plugin.basePath }}
proxy:
# re-proxy the existing backend service, since the backend is normally exposed to only allow
# GET's, but our reverse proxy in the nginx config supports any method
# https://github.com/openshift/console/blob/master/pkg/plugins/handlers.go
- alias: reproxy
authorization: None
endpoint:
service:
name: {{ template "openshift-console-plugin.name" . }}
namespace: {{ .Release.Namespace }}
port: {{ .Values.plugin.port }}
type: Service
8 changes: 5 additions & 3 deletions src/components/pod/PodTab.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,12 @@ import {
PageSection,
Spinner,
} from '@patternfly/react-core';
import { FalconClient } from 'crowdstrike-falcon';
import { FalconClient, FalconCloud } from 'crowdstrike-falcon';
import { useK8sModel, k8sGet } from '@openshift-console/dynamic-plugin-sdk';
import ImageDetectionsCard from './ImageDetectionsCard';
import ImageVulnsCard from './ImageVulnsCard';
import RuntimeDetectionsCard from './RuntimeDetectionsCard';
import proxiedFetchFactory from '../shared/ProxiedFetch';

export default function PodDetails({ obj }) {
const [loading, setLoading] = React.useState(true);
Expand All @@ -29,10 +30,11 @@ export default function PodDetails({ obj }) {
React.useEffect(() => {
k8sGet({ model: secretModel, name: 'crowdstrike-api', ns: obj.metadata.namespace })
.then((secret) => {
const cloud: FalconCloud = atob(secret['data'].cloud) as FalconCloud;
setClient(
new FalconClient({
cloud: 'us-2', // TODO: cast cloud to FalconCloud type
// cloud: atob(secret['data'].cloud),
fetchApi: proxiedFetchFactory(cloud),
cloud: cloud,
clientId: atob(secret['data'].client_id),
clientSecret: atob(secret['data'].client_secret),
}),
Expand Down
19 changes: 19 additions & 0 deletions src/components/shared/ProxiedFetch.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import { consoleFetch } from '@openshift-console/dynamic-plugin-sdk';

export default function proxiedFetchFactory(cloud) {
return (url, options) => {
// make requests to our reverse proxy instead of directly to the CrowdStrike API, since it doesn't
// support arbitrary CORS
const proxyBase = '/api/proxy/plugin/falcon-openshift-console-plugin/reproxy/crwdapi';
const path = url.substr(url.indexOf('.com') + 4);

// add region to request header so our reverse proxy can forward correctly
if (!options.headers) {
options.headers = {};
}
options.headers['X-CS-REGION'] = cloud;

// use consoleFetch to ensure CSRF headers are added
return consoleFetch(proxyBase + path, options);
};
}
7 changes: 5 additions & 2 deletions src/components/virt/VirtualMachineTab.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import {
DeviceapiDeviceSwagger,
DomainBaseAPIVulnerabilityV2,
FalconClient,
FalconCloud,
} from 'crowdstrike-falcon';
import { k8sGet, useK8sModel } from '@openshift-console/dynamic-plugin-sdk';
import DetectionsTable from './DetectionsTable';
Expand All @@ -24,6 +25,7 @@ import VulnsTable from './VulnsTable';
import '../missing-pf-styles.css';
import './style.css';
import SecurityOverview from './SecurityOverview';
import proxiedFetchFactory from '../shared/ProxiedFetch';

export default function VirtualMachineTab({ obj }) {
const [loading, setLoading] = React.useState(true);
Expand All @@ -45,10 +47,11 @@ export default function VirtualMachineTab({ obj }) {
React.useEffect(() => {
k8sGet({ model: secretModel, name: 'crowdstrike-api', ns: obj.metadata.namespace })
.then((secret) => {
const cloud: FalconCloud = atob(secret['data'].cloud) as FalconCloud;
setClient(
new FalconClient({
cloud: 'us-2', // TODO: cast cloud to FalconCloud type
// cloud: atob(secret['data'].cloud),
fetchApi: proxiedFetchFactory(cloud),
cloud: cloud,
clientId: atob(secret['data'].client_id),
clientSecret: atob(secret['data'].client_secret),
}),
Expand Down

0 comments on commit 369e605

Please sign in to comment.