Skip to content

Commit

Permalink
feat: Verify agent checksum (#79)
Browse files Browse the repository at this point in the history
The action now verifies the checksum after downloading the agent.

Notable changes:

- Replaced the input `_local-agent-path` with the environment variable
`_LOCAL_AGENT`.
- Both the local and downloaded agents are now installed at the same
location (`/opt/bullfrog/agent`).
  • Loading branch information
larose committed Jul 21, 2024
1 parent 0247bcb commit e5b087d
Show file tree
Hide file tree
Showing 16 changed files with 235 additions and 112 deletions.
37 changes: 21 additions & 16 deletions .github/workflows/bullfrog.yml
Original file line number Diff line number Diff line change
Expand Up @@ -40,18 +40,18 @@ jobs:
with:
egress-policy: block
allowed-domains: |
registry.npmjs.org
*.blob.core.windows.net
*.docker.io
*.golang.org
storage.googleapis.com
*.github.com
*.blob.core.windows.net
deb.debian.org
production.cloudflare.docker.com
registry.npmjs.org
storage.googleapis.com
- name: Checkout
uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7

- name: Install deps
run: sudo apt-get install libnetfilter-queue-dev

- name: Build
run: |
make bootstrap
Expand All @@ -68,7 +68,7 @@ jobs:
agent/agent
action/dist
check-dist-diff:
check-artifacts:
needs: build
runs-on: ubuntu-22.04
timeout-minutes: 5
Expand All @@ -88,9 +88,9 @@ jobs:
with:
name: build-artifacts

- name: Check if dist has changed for the action/dist folder
- name: Check Artifact Build
run: |
git diff --exit-code --quiet action/dist || (echo "action/dist has changed, please commit the changes" && exit 1)
make test.artifacts
test-audit:
needs: build
Expand All @@ -107,10 +107,11 @@ jobs:

- name: Enable egress filtering
uses: ./
env:
_LOCAL_AGENT: true
with:
allowed-domains: |
*.google.com
_local-agent-path: agent/agent
- name: Make HTTP requests
run: |
Expand All @@ -137,12 +138,13 @@ jobs:

- name: Enable egress filtering
uses: ./
env:
_LOCAL_AGENT: true
with:
allowed-domains: |
*.google.com
egress-policy: block
enable-sudo: false
_local-agent-path: agent/agent

- name: Make HTTP requests
run: source test/make_http_requests.sh
Expand All @@ -168,12 +170,13 @@ jobs:

- name: Enable egress filtering
uses: ./
env:
_LOCAL_AGENT: true
with:
allowed-domains: |
*.google.com
dns-policy: any
egress-policy: block
_local-agent-path: agent/agent

- name: Make HTTP requests
run: source test/make_http_requests.sh
Expand All @@ -198,16 +201,16 @@ jobs:

- name: Enable egress filtering
uses: ./
env:
_LOCAL_AGENT: true
with:
allowed-ips: |
172.17.0.0/16
allowed-domains: |
production.cloudflare.docker.com
docker.io
*.docker.io
production.cloudflare.docker.com
www.google.com
egress-policy: block
_local-agent-path: agent/agent

- name: Test curl calls within Docker
run: |
Expand Down Expand Up @@ -249,6 +252,7 @@ jobs:
download.docker.com
go.dev
objects.githubusercontent.com
packages.microsoft.com
vagrantcloud-files-production.s3-accelerate.amazonaws.com
vagrantcloud.com
www.google.com
Expand All @@ -262,6 +266,7 @@ jobs:

- name: Install Dependencies
run: |
sudo apt-get update
sudo apt-get install --yes vagrant virtualbox
- name: Start VM
Expand Down Expand Up @@ -309,7 +314,7 @@ jobs:
needs:
[
build,
check-dist-diff,
check-artifacts,
test-audit,
test-block,
test-block-but-allow-any-dns-requests,
Expand Down
11 changes: 11 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,17 @@ test.integration: test.integration.block
test.integration.block:
vagrant ssh --command "bash /vagrant/test/block.sh"

.PHONY: test.artifacts
test.artifacts: test.artifacts.action test.artifacts.agent

.PHONY: test.artifacts.action
test.artifacts.action:
cd $(ACTION_DIRECTORY) && make test.artifacts

.PHONY: test.artifacts.agent
test.artifacts.agent:
cd $(AGENT_DIRECTORY) && make test.artifacts

.PHONY: test.lint
test.lint: test.lint.action test.lint.agent

Expand Down
5 changes: 0 additions & 5 deletions action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -32,11 +32,6 @@ inputs:
type: string
default: ${{ runner.temp }}/agent-logs

_local-agent-path:
description: "(Internal) Path to a local agent binary to use instead of fetching it from Github. This is useful for testing changes to the agent without releasing it. The path is relative to the root action directory (where this action.yml is located)."
type: string
default: ""

runs:
using: "node20"
main: "action/dist/main.js"
Expand Down
4 changes: 4 additions & 0 deletions action/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,10 @@ build:
fix:
npx eslint --fix .

.PHONY: test.artifacts
test.artifacts:
git diff --exit-code --quiet dist || (echo "dist has changed, please commit the changes" && exit 1)

.PHONY: test.lint
test.lint:
npx eslint .
Expand Down
101 changes: 66 additions & 35 deletions action/dist/main.js
Original file line number Diff line number Diff line change
Expand Up @@ -19015,14 +19015,15 @@ function parseInputs() {
if (dnsPolicy !== ALLOWED_DOMAINS_ONLY && dnsPolicy !== ANY) {
throw new Error(`dns-policy must be '${ALLOWED_DOMAINS_ONLY}' or '${ANY}'`);
}
const localAgent = process.env["_LOCAL_AGENT"]?.toLowerCase() === "true";
return {
allowedDomains,
allowedIps,
dnsPolicy,
enableSudo: core.getBooleanInput("enable-sudo"),
egressPolicy,
localAgent,
logDirectory: core.getInput("_log-directory", { required: true }),
localAgentPath: core.getInput("_local-agent-path"),
agentDownloadBaseURL: core.getInput("_agent-download-base-url")
};
}
Expand Down Expand Up @@ -19067,6 +19068,54 @@ async function waitForStringInFile({

// src/main.ts
var exec = import_node_util.default.promisify(import_node_child_process.exec);
async function copyLocalAgent({ agentDirectory }) {
await import_promises3.default.mkdir(import_node_path.default.dirname(AGENT_INSTALL_PATH), { recursive: true });
await import_promises3.default.cp(import_node_path.default.join(agentDirectory, "agent"), AGENT_INSTALL_PATH);
}
async function downloadAgent({
actionDirectory,
agentDirectory,
version: version2,
agentDownloadBaseURL
}) {
console.log(`Downloading agent v${version2}`);
const { status } = (0, import_node_child_process.spawnSync)(
"bash",
[
import_node_path.default.join(actionDirectory, "scripts", "download_agent.sh"),
`v${version2}`,
agentDownloadBaseURL
],
{
env: {
AGENT_DIRECTORY: agentDirectory
},
stdio: "inherit"
}
);
if (status !== 0) {
throw new Error("Couldn't download agent");
}
}
async function installAgent({
actionDirectory,
agentDirectory,
localAgent,
version: version2,
agentDownloadBaseURL
}) {
if (localAgent) {
await copyLocalAgent({ agentDirectory });
} else {
await downloadAgent({
actionDirectory,
agentDirectory,
agentDownloadBaseURL,
version: version2
});
}
await verifyAgent({ agentDirectory });
}
function installPackages() {
console.log("Installing packages");
const { status } = (0, import_node_child_process.spawnSync)(
Expand Down Expand Up @@ -19124,35 +19173,8 @@ async function startTetragon({
});
console.timeEnd("Tetragon startup time");
}
async function downloadAgent({
actionDirectory,
localAgentPath,
version: version2,
agentDownloadBaseURL
}) {
if (localAgentPath !== "") {
const absolutePath = import_node_path.default.join(actionDirectory, "..", localAgentPath);
core3.debug(`Using local agent from ${absolutePath}`);
return absolutePath;
}
console.log(`Downloading agent v${version2}`);
const { status } = (0, import_node_child_process.spawnSync)(
"bash",
[
import_node_path.default.join(actionDirectory, "scripts", "download_agent.sh"),
`v${version2}`,
agentDownloadBaseURL
],
{ stdio: "inherit" }
);
if (status !== 0) {
throw new Error("Couldn't download agent");
}
return AGENT_INSTALL_PATH;
}
async function startAgent({
agentDirectory,
agentPath,
agentLogFilepath,
allowedDomains,
allowedIps,
Expand All @@ -19175,14 +19197,14 @@ async function startAgent({
console.log("loaded audit rules");
}
const agentOut = await import_promises3.default.open(agentLogFilepath, "a");
console.log(`Starting agent from ${agentPath}`);
console.log(`Starting agent from ${AGENT_INSTALL_PATH}`);
console.time("Agent startup time");
await exec(`sudo chmod +x ${agentPath}`);
await exec(`sudo chmod +x ${AGENT_INSTALL_PATH}`);
const allowedDomainsFlag = allowedDomains.length > 0 ? `--allowed-domains ${allowedDomains.join(",")}` : "";
const allowedIpsFlag = allowedIps.length > 0 ? `--allowed-ips ${allowedIps.join(",")}` : "";
const enableSudoFlag = enableSudo ? "true" : "false";
const agentCommand = [
agentPath,
AGENT_INSTALL_PATH,
"--dns-policy",
dnsPolicy,
"--egress-policy",
Expand All @@ -19202,6 +19224,15 @@ async function startAgent({
}
console.timeEnd("Agent startup time");
}
async function verifyAgent({ agentDirectory }) {
const agentDirName = import_node_path.default.dirname(AGENT_INSTALL_PATH);
const src = import_node_path.default.join(agentDirectory, "agent.sha256");
const dest = import_node_path.default.join(agentDirName, "agent.sha256");
await import_promises3.default.cp(src, dest);
await exec("sha256sum --check --strict agent.sha256", {
cwd: agentDirName
});
}
async function main() {
const {
agentDownloadBaseURL,
Expand All @@ -19210,7 +19241,7 @@ async function main() {
dnsPolicy,
egressPolicy,
enableSudo,
localAgentPath,
localAgent,
logDirectory
} = parseInputs();
const actionDirectory = import_node_path.default.join(__dirname, "..");
Expand All @@ -19224,15 +19255,15 @@ async function main() {
await startTetragon({
tetragonLogFilepath
});
const agentPath = await downloadAgent({
await installAgent({
actionDirectory,
localAgentPath,
agentDirectory,
localAgent,
version: pkg.version,
agentDownloadBaseURL
});
await startAgent({
agentLogFilepath,
agentPath,
agentDirectory,
allowedDomains,
allowedIps,
Expand Down
6 changes: 3 additions & 3 deletions action/dist/main.js.map

Large diffs are not rendered by default.

3 changes: 2 additions & 1 deletion action/dist/post.js
Original file line number Diff line number Diff line change
Expand Up @@ -19013,14 +19013,15 @@ function parseInputs() {
if (dnsPolicy !== ALLOWED_DOMAINS_ONLY && dnsPolicy !== ANY) {
throw new Error(`dns-policy must be '${ALLOWED_DOMAINS_ONLY}' or '${ANY}'`);
}
const localAgent = process.env["_LOCAL_AGENT"]?.toLowerCase() === "true";
return {
allowedDomains,
allowedIps,
dnsPolicy,
enableSudo: core.getBooleanInput("enable-sudo"),
egressPolicy,
localAgent,
logDirectory: core.getInput("_log-directory", { required: true }),
localAgentPath: core.getInput("_local-agent-path"),
agentDownloadBaseURL: core.getInput("_agent-download-base-url")
};
}
Expand Down
4 changes: 2 additions & 2 deletions action/dist/post.js.map

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions action/scripts/download_agent.sh
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ if [ -f "$AGENT_FILE" ]; then
else
curl -L ${DOWNLOAD_URL}/${VERSION}/agent.tar.gz -o "$AGENT_FILE"
fi

tar -xvf "$AGENT_FILE" -C $TMP_DIR

mkdir -p "$FINAL_BIN_DIR"
Expand Down
6 changes: 4 additions & 2 deletions action/src/inputs.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,8 @@ export interface Inputs {
dnsPolicy: DnsPolicy;
enableSudo: boolean;
egressPolicy: EgressPolicy;
localAgent: boolean;
logDirectory: string;
localAgentPath: string;
agentDownloadBaseURL: string;
}

Expand Down Expand Up @@ -59,14 +59,16 @@ export function parseInputs(): Inputs {
throw new Error(`dns-policy must be '${ALLOWED_DOMAINS_ONLY}' or '${ANY}'`);
}

const localAgent = process.env["_LOCAL_AGENT"]?.toLowerCase() === "true";

return {
allowedDomains,
allowedIps,
dnsPolicy,
enableSudo: core.getBooleanInput("enable-sudo"),
egressPolicy,
localAgent,
logDirectory: core.getInput("_log-directory", { required: true }),
localAgentPath: core.getInput("_local-agent-path"),
agentDownloadBaseURL: core.getInput("_agent-download-base-url"),
};
}
Loading

0 comments on commit e5b087d

Please sign in to comment.