{"id":22071480,"url":"https://github.com/zonque/restic-scripts","last_synced_at":"2025-10-17T22:03:09.126Z","repository":{"id":66926939,"uuid":"545675281","full_name":"zonque/restic-scripts","owner":"zonque","description":"Support scripts for Restic on S3","archived":false,"fork":false,"pushed_at":"2023-01-30T11:04:07.000Z","size":4,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-02-05T02:19:00.115Z","etag":null,"topics":["backup","restic","s3"],"latest_commit_sha":null,"homepage":"","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/zonque.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2022-10-04T19:40:56.000Z","updated_at":"2022-10-04T19:46:34.000Z","dependencies_parsed_at":"2023-02-23T04:30:31.064Z","dependency_job_id":null,"html_url":"https://github.com/zonque/restic-scripts","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/zonque%2Frestic-scripts","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/zonque%2Frestic-scripts/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/zonque%2Frestic-scripts/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/zonque%2Frestic-scripts/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/zonque","download_url":"https://codeload.github.com/zonque/restic-scripts/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":245153896,"owners_count":20569408,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["backup","restic","s3"],"created_at":"2024-11-30T20:31:48.255Z","updated_at":"2025-10-17T22:03:04.066Z","avatar_url":"https://github.com/zonque.png","language":"Python","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Support scripts for Restic on S3\n\nWith [Restic](https://restic.readthedocs.io) backups on [S3](https://en.wikipedia.org/wiki/Amazon_S3),\nsome configuration is needed to make the setup tamper-proof.\n\n## S3 configuration\n\nThe user credentials stored on the host running the backups should have a policy in place\nthat only allows `GetObject` and `PutObject` bucket-wide, and `DeleteObject` for objects\nin the `locks/` folder:\n\n```\n{\n  \"Version\": \"2012-10-17\",\n  \"Statement\": [\n    {\n      \"Effect\": \"Allow\",\n      \"Action\": [\n        \"s3:PutObject\",\n        \"s3:GetObject\"\n      ],\n      \"Resource\": [\n        \"arn:aws:s3:::BUCKETNAME\",\n        \"arn:aws:s3:::BUCKETNAME/*\"\n      ]\n    },\n    {\n      \"Effect\": \"Allow\",\n      \"Action\": \"s3:DeleteObject\",\n      \"Resource\": \"arn:aws:s3:::BUCKETNAME/locks/*\"\n    },\n    {\n      \"Effect\": \"Allow\",\n      \"Action\": [\n        \"s3:ListBucket\",\n        \"s3:GetBucketLocation\"\n      ],\n      \"Resource\": \"arn:aws:s3:::BUCKETNAME\"\n    }\n  ]\n}\n```\n\nHowever, even with the above policy in place, an attacker that obtains the credentials\ncan still overwrite objects in the bucket, as creating and replacing an object in S3 is\nboth covered by the `PutObject` action.\n\nHence, S3 buckets that hold Restic backups should be configured to have object versioning\nenabled. This way, objects that are overwritten can be recovered. This however has the\nside-effect that files can no longer be fully deleted by prunes.\n\n# Scripts\n\nAll scripts require `AWS_ACCESS_KEY_ID` and `AWS_SECRET_ACCESS_KEY` to be set in the environment.\n\n## Check\n\nWhen called with the `check` argument, the `check-versions.py` script traverses through the\ngiven bucket (passed in the `RESTIC_REPOSITORY` environment variable) and finds all objects\nthat have more than one version. This might be an indicaton for an attempt to tamper with the\nfiles. Objects with a prefix of `/locks` are ignored.\n\nIf any such object is found, the script will exit with code 1.\n\n## Prune\n\nAs described above, a simple `restic prune` will not free up the space in S3, as the\nobjects are merely marked for deletion due to the bucket versioning logic.\n\nWhen called with the `prune` argument, the `check-versions.py` script traverses through the\ngiven bucket (passed in the `RESTIC_REPOSITORY` environment variable) and finds all deleted\nobjects that have versions and deletes them. This will then free up the space in the storage\nprovider.\n\n## Umbrella script for pruning\n\n`prune.sh` is a script that must be called with a restic repository URL as 1st and the corresponding\npassword as the 2nd argument. It will then first check for signs of tampering, the call `restic prune`\nand eventually `check-version.py prune` to complete the work.\n\n## Sanity check\n\n`check-snapshot.py` takes a Restic URL as argument and scans the snapshots in the bucket.\n\nIt then performs two checks:\n\n* Assert that the number of snapshots taken in the last 48h is twice the amount than the number\n  of snapshots in the last 24h. This way, anomalities in backup behaviour can be detected\n* Assert that there was at least one snapshot taken within the last 24h.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fzonque%2Frestic-scripts","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fzonque%2Frestic-scripts","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fzonque%2Frestic-scripts/lists"}