diff --git a/.woodpecker.yml b/.woodpecker.yml new file mode 100644 index 0000000..9df2fa5 --- /dev/null +++ b/.woodpecker.yml @@ -0,0 +1,144 @@ +labels: + hostname: "macmini7" +clone: + git: + image: woodpeckerci/plugin-git + settings: + partial: false + depth: 1 +steps: + # Build Step for staging Branch + build-staging: + name: build-staging + image: woodpeckerci/plugin-docker-buildx + secrets: [REGISTRY_USER, REGISTRY_PASSWORD] + volumes: + - /var/run/docker.sock:/var/run/docker.sock + commands: + - echo "Building application for staging branch" + - echo "$${REGISTRY_PASSWORD}" | docker login -u "$${REGISTRY_USER}" --password-stdin git.nixc.us + - echo compose build + - docker compose -f docker-compose.staging.yml build + when: + branch: main + event: push + # path: + # include: [ 'stack.production.yml', 'stack.staging.yml', 'docker-compose.staging.yml', 'docker-compose.production.yml', 'Dockerfile', '*.tests.ts' ] + + deploy-new: + name: deploy-new + when: + branch: main + # path: + # include: [ 'stack.production.yml', 'stack.staging.yml', 'docker-compose.staging.yml', 'docker-compose.production.yml', 'Dockerfile', '*.tests.ts' ] + image: woodpeckerci/plugin-docker-buildx + secrets: [REGISTRY_USER, REGISTRY_PASSWORD] + volumes: + - /var/run/docker.sock:/var/run/docker.sock + commands: + - echo "$${REGISTRY_PASSWORD}" | docker login -u "$${REGISTRY_USER}" --password-stdin git.nixc.us + - echo compose push + - docker compose -f docker-compose.staging.yml push + # - docker stack deploy --with-registry-auth -c ./stack.staging.yml $${CI_REPO_NAME}-staging + + # # Wait for Deploy to Complete + # wait-for-deploy-staging: + # name: wait-for-deploy-staging + # image: woodpeckerci/plugin-git + # commands: + # - echo "Waiting for staging deploy step to complete rollout." + # - sleep 60 + # when: + # - branch: main + # - event: push + + # # Run Automated Tests on staging Branch + # test-staging: + # name: run-tests-staging + # image: git.nixc.us/colin/playwright:latest + # secrets: [ base_url ] + # when: + # - branch: main + # - event: push + # - path: + # include: [ 'tests/', 'src/','docker-compose.staging.yml', 'docker-compose.production.yml', '*.tests.ts' ] # Specify paths relevant to tests + # volumes: + # - /var/run/docker.sock:/var/run/docker.sock:ro + + cleanup-staging: + name: cleanup-staging + when: + branch: main + # path: + # include: [ 'stack.production.yml', 'stack.staging.yml', 'docker-compose.staging.yml', 'docker-compose.production.yml', 'Dockerfile', '*.tests.ts' ] + image: woodpeckerci/plugin-docker-buildx + secrets: [REGISTRY_USER, REGISTRY_PASSWORD] + volumes: + - /var/run/docker.sock:/var/run/docker.sock + commands: + # - docker stack rm $${CI_REPO_NAME}-staging + ## added fault tolerance for docker stack rm + # - for i in {1..5}; do docker stack rm ${CI_REPO_NAME}-staging && break || sleep 10; done + - docker compose -f docker-compose.staging.yml down + - docker compose -f docker-compose.staging.yml rm -f + + # Build Step for staging Branch + build-build-push-production: + name: build-build-push-production + image: woodpeckerci/plugin-docker-buildx + secrets: [REGISTRY_USER, REGISTRY_PASSWORD] + volumes: + - /var/run/docker.sock:/var/run/docker.sock + commands: + - echo "Building application for staging branch" + - echo "$${REGISTRY_PASSWORD}" | docker login -u "$${REGISTRY_USER}" --password-stdin git.nixc.us + - echo compose build + - docker compose -f docker-compose.production.yml build + - docker compose -f docker-compose.production.yml push + when: + branch: main + event: [push, cron] + # path: + # include: [ 'stack.production.yml', 'stack.staging.yml', 'docker-compose.staging.yml', 'docker-compose.production.yml', 'Dockerfile', '*.tests.ts' ] + + # Deploy to Production Branch + deploy-production: + name: deploy-production + image: woodpeckerci/plugin-docker-buildx + secrets: [REGISTRY_USER, REGISTRY_PASSWORD] + volumes: + - /var/run/docker.sock:/var/run/docker.sock + commands: + - echo "$${REGISTRY_PASSWORD}" | docker login -u "$${REGISTRY_USER}" --password-stdin git.nixc.us + # - docker stack deploy --with-registry-auth -c ./stack.production.yml $${CI_REPO_NAME} + - docker image rm git.nixc.us/colin/$${CI_REPO_NAME}:production + when: + branch: main + event: [push, cron] + # path: + # include: [ 'stack.production.yml', 'stack.staging.yml', 'docker-compose.staging.yml', 'docker-compose.production.yml', 'Dockerfile', '*.tests.ts' ] + + + # # Wait for Deploy to Complete + # wait-for-deploy-production: + # name: wait-for-deploy-production + # image: woodpeckerci/plugin-git + # commands: + # - echo "Waiting for deploy step to complete rollout." + # - sleep 60 + # when: + # branch: main + # event: push + + # # Run Post-Deployment Smoke Tests + # post-deploy-smoke-tests-git-nixc-us: + # name: run-post-deploy-smoke-tests-git-nixc-us + # image: git.nixc.us/colin/playwright:latest + # # secrets: [TEST_USER, TEST_PASSWORD] + # environment: + # - BASE_URL=https://git.nixc.us + # when: + # branch: main + # event: push + # # path: + # # include: [ 'stack.production.yml', 'stack.staging.yml', 'docker-compose.staging.yml', 'docker-compose.production.yml', 'Dockerfile', '*.tests.ts' ] \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..a8de031 --- /dev/null +++ b/README.md @@ -0,0 +1,73 @@ + +# Known weaknesses and caveats +There is currently no significantly advanced validation except that it builds, and the packages it draws from are unlikely to break without us knowing. This doesn't validate the efficacy of the tools in this container yet; it may be something added later. + +## ToDo + +* [ ] Add actual testing other than just compiling staging tests. +* [ ] Safely add known virus files to the repository for scanning during e2e testing. +* [ ] Consider a consistent reporting system for e2e tests like this. +* [ ] Enact quarantine measure tests as well. + +## Disclaimer + +You will also need to understand what a virus scanner's scope is; it is not an assertion that the machine is now considered safe after a scan. It's predominantly a measurement tool at best. It increases observability and allows some actions to be taken on detectable things. They aren't a tool for promising that a system is safe going forward. The IT staff should always consider the level of remediation steps needed to be taken at the time of positive detection. + +## Considerations + +Do understand that when something is out of specification in a server, this is like 90% confidence to be working regularly. This tool can periodically scan a system's files in a way that should be less obvious to advanced attackers and less likely to be modified on a system as docker containers are cryptographically signed and jailed away from typical user space. The tool offers a run mode that can be used to enact quarantine measures. It is theoretical as it has not been actively tested in the current state. However, it's only a convenience function as you can pull which files to erase from the scan logs. + +# Usage +Create a directory and put this compose file +`mkdir -p /root/clam/` + +then `nano /root/clam/docker-compose.yml` + +## docker-compose.yml + +```yaml +version: '3.8' + +services: + clam: + image: git.nixc.us/colin/clam:production + volumes: + - /:/scan + - ./logs:/var/log/clamav + - ./quarantine:/quarantine +``` + +Put this container in the crontab +``` +crontab -e +``` +Then add one of the below cron examples. +### Once a Week + +To run the job every Sunday at midnight: + +```cron +0 0 * * 0 /usr/bin/docker compose -f /root/clam/docker-compose.yml up -d --pull --force-recreate clamav +``` + +### Once Every Two Weeks + +Cron does not natively support a bi-weekly schedule directly. However, you can achieve this by specifying two days of the month, such as the 1st and 15th: + +```cron +0 0 1,15 * * /usr/bin/docker compose -f /root/clam/docker-compose.yml up -d --pull --force-recreate clamav +``` + +### Once a Month + +To run the job on the first day of every month at midnight: + +```cron +0 0 1 * * /usr/bin/docker compose -f /root/clam/docker-compose.yml up -d --pull --force-recreate clamav +``` + +### Notes: + +- Ensure that `/usr/bin/docker` is the correct path to your Docker binary. This path might vary depending on your system's configuration. +- Replace `/root/clam` with the actual directory path where your `docker-compose.yml` file is located. +- These cron jobs will pull the latest image and recreate the `clamav` container according to the specified schedule. Ensure that this behavior aligns with your maintenance and update policies. diff --git a/docker-compose.production.yml b/docker-compose.production.yml new file mode 100644 index 0000000..d698985 --- /dev/null +++ b/docker-compose.production.yml @@ -0,0 +1,8 @@ +version: '3.8' + +services: + clam: + build: + context: ./docker/clam/ + dockerfile: Dockerfile + image: git.nixc.us/colin/clam:production diff --git a/docker-compose.staging.yml b/docker-compose.staging.yml new file mode 100644 index 0000000..049e187 --- /dev/null +++ b/docker-compose.staging.yml @@ -0,0 +1,8 @@ +version: '3.8' + +services: + clam: + build: + context: ./docker/clam/ + dockerfile: Dockerfile + image: git.nixc.us/colin/clam:staging diff --git a/docker/clam/docker-entrypoint.sh b/docker/clam/docker-entrypoint.sh new file mode 100644 index 0000000..3408b04 --- /dev/null +++ b/docker/clam/docker-entrypoint.sh @@ -0,0 +1,51 @@ +#!/bin/sh + +MODE=${1:-"scan"} + +scan() { + echo "Running ClamAV scan..." + clamscan -r /scan --log=/var/log/clamav/clamav.log +} + +report() { + echo "Generating report..." + local log_file="/var/log/clamav/clamav.log" + if [ ! -f "$log_file" ]; then + echo "No log file found." + return + fi + local total_files=$(grep "Infected files:" "$log_file" | cut -d" " -f3) + local infected_files=$(grep "Infected files:" "$log_file" | cut -d" " -f5) + local errors=$(grep "Total errors:" "$log_file" | cut -d" " -f3) + echo "Scan Report:" + echo "Total files scanned: $total_files" + echo "Infected files found: $infected_files" + echo "Errors during scan: $errors" +} +quarantine() { + echo "Quarantining infected files..." + local log_file="/var/log/clamav/clamav.log" + local quarantine_dir="/quarantine" + mkdir -p "$quarantine_dir" + grep "FOUND" "$log_file" | cut -d" " -f1 | while read -r infected_file; do + if [ -f "$infected_file" ]; then + mv "$infected_file" "$quarantine_dir/" + fi + done +} + +case "$MODE" in + scan) + scan + ;; + report) + report + ;; + quarantine) + quarantine + ;; + *) + echo "Unknown mode: $MODE" + exit 1 + ;; +esac