diff --git a/pulumi/src/cloudflare/index.ts b/pulumi/src/cloudflare/index.ts index 366dee0..b417bb1 100644 --- a/pulumi/src/cloudflare/index.ts +++ b/pulumi/src/cloudflare/index.ts @@ -1,3 +1,5 @@ import './provider' +import './zone' import './tunnel' import './record' +import './waf' diff --git a/pulumi/src/cloudflare/record.ts b/pulumi/src/cloudflare/record.ts index 1004773..19b08f3 100644 --- a/pulumi/src/cloudflare/record.ts +++ b/pulumi/src/cloudflare/record.ts @@ -2,15 +2,7 @@ import * as cloudflare from '@pulumi/cloudflare' import * as config from '../config' import * as tunnel from './tunnel' import { provider } from './provider' - -const zone = cloudflare.getZoneOutput({ - filter: { - name: config.cloudflareConfig.zoneName, - account: { - id: config.cloudflareConfig.accountId - } - } -}, { provider }) +import { zone } from './zone' new cloudflare.DnsRecord(config.identifier, { zoneId: zone.zoneId, diff --git a/pulumi/src/cloudflare/tunnel.ts b/pulumi/src/cloudflare/tunnel.ts index 8ded6ed..f8c418b 100644 --- a/pulumi/src/cloudflare/tunnel.ts +++ b/pulumi/src/cloudflare/tunnel.ts @@ -16,7 +16,7 @@ new cloudflare.ZeroTrustTunnelCloudflaredConfig(config.identifier, { ingresses: [ { hostname: `${config.identifier}.${config.cloudflareConfig.zoneName}`, - service: `http://${config.identifier}.${config.k8sConfig.namespace}.svc.cluster.local:80` + service: 'http://localhost:80' }, { service: 'http_status:404' diff --git a/pulumi/src/cloudflare/waf.ts b/pulumi/src/cloudflare/waf.ts new file mode 100644 index 0000000..48d503c --- /dev/null +++ b/pulumi/src/cloudflare/waf.ts @@ -0,0 +1,62 @@ +import * as cloudflare from '@pulumi/cloudflare' +import { provider } from './provider' +import * as config from '../config' +import { zone } from './zone' + +const expression = [ + // Sensitive dotfiles and directories + '(http.request.uri.path contains "/.env")', + '(http.request.uri.path contains "/.git")', + '(http.request.uri.path contains "/.aws")', + '(http.request.uri.path contains "/.ssh")', + '(http.request.uri.path contains "/.terraform")', + + // CMS and framework probes + '(http.request.uri.path contains "/wp-")', + '(http.request.uri.path contains "/wordpress")', + '(http.request.uri.path contains "/xmlrpc")', + '(http.request.uri.path contains "/phpMyAdmin")', + '(http.request.uri.path contains "/phpmyadmin")', + '(http.request.uri.path contains "/pma")', + + // Admin and server management + '(http.request.uri.path contains "/admin")', + '(http.request.uri.path contains "/cgi-bin")', + '(http.request.uri.path contains "/actuator")', + '(http.request.uri.path contains "/solr")', + '(http.request.uri.path contains "/telescope")', + '(http.request.uri.path contains "/vendor")', + '(http.request.uri.path contains "/invoker")', + '(http.request.uri.path contains "/balancer-manager")', + + // Credential and config probes + '(http.request.uri.path contains "/credentials")', + '(http.request.uri.path contains "/known_hosts")', + '(http.request.uri.path contains "sendgrid")', + '(http.request.uri.path contains "codecommit")', + '(http.request.uri.path contains "/env.cfg")', + + // Dangerous file extensions + '(http.request.uri.path contains ".php")', + '(http.request.uri.path contains ".asp")', + '(http.request.uri.path contains ".jsp")', + '(http.request.uri.path contains ".cgi")', + '(http.request.uri.path contains ".yml")', + '(http.request.uri.path contains ".xml")', + '(http.request.uri.path contains ".bak")', + '(http.request.uri.path contains ".rb")', +].join(' or ') + +new cloudflare.Ruleset(`${config.identifier}-waf`, { + zoneId: zone.zoneId, + name: 'Block vulnerability scanners', + kind: 'zone', + phase: 'http_request_firewall_custom', + rules: [{ + ref: 'block_scan_probes', + description: 'Block common vulnerability scanner paths and file extensions', + enabled: true, + expression, + action: 'block', + }] +}, { provider }) diff --git a/pulumi/src/cloudflare/zone.ts b/pulumi/src/cloudflare/zone.ts new file mode 100644 index 0000000..b0fe5d2 --- /dev/null +++ b/pulumi/src/cloudflare/zone.ts @@ -0,0 +1,12 @@ +import * as cloudflare from '@pulumi/cloudflare' +import { provider } from './provider' +import * as config from '../config' + +export const zone = cloudflare.getZoneOutput({ + filter: { + name: config.cloudflareConfig.zoneName, + account: { + id: config.cloudflareConfig.accountId + } + } +}, { provider }) diff --git a/pulumi/src/docker/image.ts b/pulumi/src/docker/image.ts index 29928e4..705808e 100644 --- a/pulumi/src/docker/image.ts +++ b/pulumi/src/docker/image.ts @@ -7,6 +7,8 @@ import * as config from '../config' const registryUri = config.dockerConfig.registryUri const registryHost = registryUri.split('/')[0] +const isGitHubActions = !!process.env.GITHUB_ACTIONS + export const image = new dockerBuild.Image(config.identifier, { tags: [ pulumi.interpolate`${registryUri}/${config.identifier}` @@ -23,6 +25,8 @@ export const image = new dockerBuild.Image(config.identifier, { username: 'oauth2accesstoken', password: config.dockerConfig.registryAccessToken, }], + cacheFrom: isGitHubActions ? [{ gha: {} }] : [], + cacheTo: isGitHubActions ? [{ gha: { mode: dockerBuild.CacheMode.Max, ignoreError: true } }] : [], }, { provider }) export const imageRef = image.ref