In five minutes, with no cloud account and no credentials, you will watch Pépin find four real deviations in a configuration, then fix them and see the verdict flip. The repository ships example inventories: one deliberately vulnerable, one fixed. This is the shortest way to understand what the tool looks at before pointing it at your own infrastructure.
What you will learn
- Run a scan and get a non-compliant verdict.
- Read a deviation: the control, the offending resource, the observation, the remediation.
- Fix the four deviations and watch the exit code drop back to zero.
- Recognise why a rule open to the internet is not always a deviation.
Getting the tool ready
No cloud account is needed for this page. The shortest path is to build from source, which requires Go 1.26 or newer:
git clone https://github.com/stephrobert/pepincd pepingo build -o pepin ../pepin versionThe output prints the version number. If you would rather use a signed binary, a container image or a package manager, the installation page covers them; to get a feel for the tool, building from source is enough and sidesteps any question of trusting a downloaded binary.
The first scan
The repository contains a deliberately misconfigured Scaleway inventory. It holds three resources: an object storage bucket, an access key and a firewall rule.
./pepin scan scaleway examples/scaleway/inventory.jsonThe output ends with an unambiguous summary:
Verdict : NON CONFORME
🔴 CRITICAL 2 🟠 HIGH 2 🟡 MEDIUM 0 🔵 LOW 0Check the exit code, since it is what will later drive your pipeline:
echo $?It is 1, meaning at least one deviation of critical or high severity was established.
Reading the four deviations
Three resources produced four deviations: the access key alone triggers two, for two different reasons.
| Severity | Control | Resource | What is observed |
|---|---|---|---|
| CRITICAL | iam_accesskey_expiration_set | the access key | no expiry date: a leak would stay exploitable indefinitely |
| CRITICAL | objectstorage_bucket_public_access | backups-prod | an ACL grants access to the global AllUsers group |
| HIGH | iam_no_root_access_key | ci-deploy | the key is attached to the root account, bypassing IAM policies |
| HIGH | network_securitygroup_allow_ingress_from_internet_to_tcp_port_22 | sg-1 | SSH accepted from the internet |
Every deviation comes with its remediation, not just its finding, and a link to the control it names:
Remediation Restrict the rule to legitimate sources and ports (administration CIDR, bastion, VPN); never expose a sensitive service to 0.0.0.0/0.
↳ docs: …/socle/referentiel/cloud/exposition-filtrage-reseau/#socle-cld-net-1Fixing, one cause at a time
The inventory is a plain JSON file: provider, then a list of resources, each
carrying a type, an identifier and its attributes. Here is what the fixed
version changes, deviation by deviation.
-
The exposed bucket
The ACL granting read access to the global
AllUsersgroup is replaced by a named grant on the owner, and versioning is turned on."acl_grants": [{ "grantee": { "type": "CanonicalUser", "id": "owner-id" }, "permission": "FULL_CONTROL" }],"versioning": "Enabled" -
The key attached to the root account
It is attached to an application rather than to a person or to the root account. That is the distinction between a human identity and a machine one.
"root_owned": false,"application_id": "22222222-2222-2222-2222-222222222222" -
The key with no expiry
An expiry date is set. It turns rotation into an obligation rather than a good intention.
"expiration_date": "2027-06-30T00:00:00Z" -
SSH open to the world
The source range moves from
0.0.0.0/0to an administration network."cidrs": ["10.0.0.0/8"],"port_from": 22,"port_to": 22
Checking that the verdict flips
./pepin scan scaleway examples/scaleway/inventory-ok.jsonecho $?The exit code is now 0, and the verdict deserves to be read word by word:
✓ No deviations found in the audited scope.
Verdict : conforme sur le périmètre évalué (aucune non-conformité détectée, 12 contrôles conformes)"Within the evaluated scope", and twelve compliant controls. Pépin does not say "your cloud is safe": it says what it checked and how many controls establish it. That is the difference between a result and a promise.
The counter-example that proves the rule thinks
Look more closely at the fixed inventory: it holds four resources, one more
than the vulnerable one. The new one is a firewall rule accepting traffic from
0.0.0.0/0.
{ "type": "security_group_rule", "attributes": { "direction": "inbound", "action": "accept", "protocol": "tcp", "cidrs": ["0.0.0.0/0"], "port_from": 443, "port_to": 443 }}And the scan stays compliant. That is deliberate: exposing port 443 to the
world is what a web server does, whereas exposing port 22 is not. A scanner
flagging every rule containing 0.0.0.0/0 would raise a false positive on every
web server, and you would very quickly learn to ignore its alerts.
What this scan did not prove
The compliant verdict covers twelve controls, not the fifty-seven of the
referential. The assessment format shows it plainly:
./pepin scan scaleway examples/scaleway/inventory.json -f assessmentOn the vulnerable inventory, the real breakdown is 4 deviations, 7 compliant, 2 not applicable and 14 not evaluated. Those fourteen controls neither passed nor failed: the required data was not in the inventory, and each one carries its reason.
compute_instance_has_security_group no resource of type "compute_instance" in the evaluated inventoryThat makes sense here, since the example inventory contains no machines. But it is exactly what will happen on your own infrastructure if your credentials lack a read permission: the control will not be evaluated, and it will say so instead of counting as a success.
Moving to your own infrastructure
Two paths open up, and they answer different questions.
| What you want to know | The command |
|---|---|
| Is what I am about to deploy correct? | terraform show -json tfplan > plan.json then pepin scan scaleway --terraform plan.json |
| Is what is actually running correct? | pepin scan scaleway --live --region fr-par |
The Terraform plan only sees what your code declares. The live collection also sees what nobody declared, and that is often where the surprises hide.
Key points
- A scan can be explored with no cloud account: the example inventories in the repository are enough.
- The exit code is 1 as soon as a critical or high deviation is established, 0 otherwise.
- One resource can produce several deviations: the access key triggers two, for two distinct reasons.
- Every deviation carries its remediation and its normative reference, not just a finding.
- Two identifiers coexist: the normative reference for conversations, the technical name for writing an exception.
- The compliant verdict is qualified by the number of controls that establish it, twelve here.
- Opening port 443 to the world triggers nothing, opening port 22 does: the rule judges the use, not the presence of
0.0.0.0/0. - Fourteen controls out of twenty-seven could not be evaluated for lack of data, and they say so.
External resources
- Example inventories in the repository: the fixtures used on this page, and their Outscale and Exoscale counterparts.
terraform showdocumentation: producing the JSON plan Pépin expects.