🖥️ infisical/infisical
Infisical is the open source security infrastructure platform that teams use for secrets, certificates, privileged access management, and AI agent access.
Infisical/infisical
1 like · 149 views
Mi opinión: cifrar con SOPS o dotenvx y commitear ya es un gran salto. Un servidor se justifica si necesitas rotación.
¿Dónde guardas tus secretos hoy?
Repos:
Infisical/infisical
getsops/sops
openbao/openbao
dotenvx/dotenvx
1 like · 3 views
Infisical : une plateforme Open Source permettant de sécuriser les secrets, les certificats, les accès et les agents d'IA.
👉 Infisical/infisical t.co
20 likes · 3 reposts · 1,253 views
Infisical : une plateforme Open Source permettant de sécuriser les secrets, les certificats, les accès et les agents d'IA.
👉 Infisical/infisical
4 likes
Stop Storing Secrets in GitHub Actions (and the One Wildcard That Opens Your Vault to Every Repo on GitHub)
CI/CD pipelines are one of the most attacked links in the software supply chain, and the usual root cause is the same: long-lived credentials stored as CI provider secrets. A CLIENT_ID/CLIENT_SECRET pasted into GitHub never expires, isn't bound to an execution context, and if it leaks (a log, a malicious fork, a compromised dependency) it is valid from anywhere.
The alternative is workload identity federation: the job doesn't present a secret it holds, but a signed statement about who it is and in what context it runs. It is the same model AWS (IAM OIDC provider), GCP (Workload Identity Federation) and Azure (federated credentials) offer for their clouds. Here I apply it to a secrets manager, Infisical, and focus on what is rarely explained: the trust model, a recent GitHub change that breaks older configurations, and how to configure it without opening a hole.
> All examples use placeholders (<OWNER>, <OWNER_ID>, <IDENTITY_ID>, infisical.example.com). Replace them with your own values.
1. Threat model
| Threat | Static secret | Scoped OIDC |
|---|---|---|
| Secret leaked in logs or artifacts | Credential valid until rotated | Token lives for minutes and is bound to an audience |
| Malicious workflow from a fork or PR | Can exfiltrate the secret if exposed | GitHub doesn't issue OIDC tokens to fork PRs, and the subject wouldn't match anyway |
| Third-party repo that knows your URL | N/A | Real risk if the subject is loose (section 4) |
| Rotation and revocation | Manual, with exposure windows | Nothing to rotate; revoke by removing the identity |
| Attribution | One shared secret, no traceability | Every login is tied to a repo, branch and workflow |
Assumptions: GitHub is the identity provider (IdP) and is trusted; GitHub-hosted runners are ephemeral; an attacker with write access to a protected branch is already inside the perimeter.
2. How the flow works
sequenceDiagram
participant J as Job (GitHub runner)
participant G as GitHub OIDC IdP
participant I as Infisical
J->>G: 1. Request JWT (audience = A)
G-->>J: 2. Signed JWT (RS256)
J->>I: 3. POST /api/v1/auth/oidc-auth/login {identityId, jwt}
I->>G: 4. Fetch .well-known + JWKS
G-->>I: 5. Public keys
Note over I: 6. Verify signature and claims (iss, aud, sub, claims)
I-->>J: 7. Short-lived access token
J->>I: 8. Read secrets with that token
What matters:
- The JWT (RFC 7519) is signed by GitHub with a key published in its JWKS. Infisical verifies the signature against that JWKS, so it must be able to reach token.actions.githubusercontent.com outbound (egress). If you self-host behind a strict firewall, that's the first place to look.
- The token has a very short lifetime (minutes) and is issued on demand, per job.
- The audience is chosen by whoever requests the token. It is not a secret and GitHub doesn't fix it.
- Infisical's login endpoint takes identityId and jwt (application/x-www-form-urlencoded).
3. Relevant claims in GitHub's token
| Claim | Example | Use |
|---|---|---|
| iss | https://token.actions.githubusercontent.com | Same for all of GitHub: doesn't discriminate |
| aud | https://infisical.example.com | Chosen by the requester: doesn't discriminate |
| sub | see section 4.2 | The main discriminator |
| repository / repository_owner | <OWNER>/<REPO> / <OWNER> | Names (mutable) |
| repository_id / repository_owner_id | numeric | Identifiers that don't change on rename |
| ref, event_name | refs/heads/main, push | Branch and trigger |
| environment | production | If the job uses a GitHub environment |
| job_workflow_ref | <OWNER>/<REPO>/.github/workflows/x.yml@refs/heads/main | Which workflow (or reusable workflow) requested the token |
4. The critical point: iss and aud protect nothing
The issuer is shared by every GitHub user, and aud is written by whoever requests the token. Anyone can create a repository, write a workflow and request a GitHub-signed JWT with aud = https://infisical.example.com. That token is cryptographically valid.
So the only barrier between your Infisical and the rest of GitHub is the identity's claims policy, especially sub. Consequences:
- Subject = * or repo:* is equivalent to opening authentication to any repository on GitHub. It's a manual confused deputy.
- A broad pattern (repo:<OWNER>/*) is only acceptable if you control everything that runs under <OWNER> and who can write to it.
- In Infisical, * in the Subject behaves like ** and also matches : and / (per its documentation). A pattern like repo:<OWNER>* would also match <OWNER>-other. Always put a / or @ separator right after the owner.
4.1. Names are mutable
Historically sub was built from organization and repository names. If an organization was deleted or renamed and someone else registered the freed name, their sub would match your pattern (a namespace reuse attack). The OIDC spec requires sub to be locally unique and never reassigned; the old format didn't guarantee that.
4.2. GitHub's 2026 change: immutable subject (it affects your setup)
GitHub introduced a default sub that includes the immutable IDs of the owner and the repository:
old format: repo:octo-org/octo-repo:ref:refs/heads/main
new format: repo:octo-org@123456/octo-repo@456789:ref:refs/heads/main
According to GitHub's documentation and changelog:
- Since July 15, 2026, new repositories use the immutable format by default, and renamed or transferred repositories move to it.
- Older repositories keep the old format until you opt in at the organization or repository level (OIDC settings UI or REST API). A preview endpoint shows what the prefix will look like.
- Not available on GitHub Enterprise Server.
Practical consequence: a policy like repo:<OWNER>/*:ref:refs/heads/main stops matching new, renamed or transferred repositories. The symptom is a 403 on a repo that "used to work" or that you just created.
Recommended setup: opt in your organizations and pin the Subject with the ID, which also closes the name-reuse attack:
repo:<OWNER>@<OWNER_ID>/*:ref:refs/heads/main
Get the owner's numeric ID with gh api users/<OWNER> --jq .id (works for organizations too). Alternatively, keep the old format and add a condition in Infisical's Claims (repository_owner_id = <OWNER_ID>). If you customize sub with include_claim_keys, note that in the immutable format owner_id and repo_id are always included.
4.3. Restricting by branch or environment
repo:<OWNER>@<OWNER_ID>/*:ref:refs/heads/main # main branch only
repo:<OWNER>@<OWNER_ID>/<REPO>@<REPO_ID>:environment:production # only jobs using the "production" environment
Restricting to main only adds security if main is protected (required reviews, no direct pushes). If anyone with write access can push a workflow to main, the boundary disappears. Using environments with required reviewers adds a human approval before the job gets the token.
5. Design: one identity per owner
Infisical supports one subject pattern per identity. Trying to cover several owners with one pattern forces you to widen it, and isolation is lost. The design I use:
| Decision | Reason |
|---|---|
| One identity per owning account (organization or user) | Tight subject, blast radius limited to one owner |
| Organization role No Access | The identity manages nothing at organization level |
| Minimal project role (Viewer), only on the projects it needs | Least privilege: read only, no write or admin |
| Remove Universal Auth if unused | Smaller surface: every active auth method is an entry point |
| Treat identity-id as public data | It is an identifier, not a secret |
6. Step by step
6.1. Infisical
1. Access Control → Machine Identities → Create: name github-ci-<owner>, organization role No Access.
2. In the identity: Authentication → Add Auth Method → OIDC Auth with:
| Field | Value |
|---|---|
| OIDC Discovery URL | https://token.actions.githubusercontent.com |
| Issuer | https://token.actions.githubusercontent.com |
| Subject | repo:<OWNER>@<OWNER_ID>/*:ref:refs/heads/main |
| Audiences | https://infisical.example.com |
| Claims (optional) | repository_owner_id = <OWNER_ID> |
3. Copy the identity's Identity ID.
4. In the project: Access Control → Machine Identities → Add identity, role Viewer.
6.2. Hardening the issued token (often skipped)
Infisical's form proposes defaults meant for general use, not for CI:
- Access Token TTL / Max TTL: 2592000 s (30 days) in the form. (The documentation also mentions 7200 s in the login response and doesn't explain the difference: check the effective value on your identity.) That's excessive for a CI job: reduce both to the longest job duration plus margin (for example 600–3600 s).
- Access Token Max Number of Uses: 0 (unlimited). If your pipeline makes a bounded number of reads, set a maximum.
- Trusted IPs: 0.0.0.0/0, ::/0 by default. GitHub-hosted runner ranges are broad and change; with self-hosted runners and a fixed IP you can restrict it.
6.3. Workflow
name: release
on:
push:
branches: [main]
permissions:
id-token: write # lets the job request the OIDC JWT
contents: read # least privilege for everything else
jobs:
build:
runs-on: ubuntu-latest
environment: production # optional: manual approval and `environment` claim
steps:
- uses: actions/checkout@v4
- name: Fetch secrets from Infisical
uses: Infisical/secrets-action@v1.0.12 # in production, pin the commit SHA
with:
method: oidc
domain: https://infisical.example.com
identity-id: <IDENTITY_ID>
project-slug: <PROJECT_SLUG>
env-slug: prod
secret-path: /
export-type: env # "file" writes a .env file instead
Notes:
- id-token: write does not grant write access to the repository; it only enables JWT issuance. Declare explicit permissions at workflow or job level so you don't depend on organization defaults.
- Pin the action to a commit SHA (not a movable tag): the action itself is third-party code that receives your claims and returns secrets.
- With export-type: env secrets become environment variables for later steps. Limit their scope to the step that uses them where possible.
- Don't request tokens in workflows triggered by untrusted code. GitHub doesn't issue OIDC tokens to pull_request runs from forks (as reported by maintainers of widely used actions; it isn't on the main OIDC documentation page). Also avoid pull_request_target combined with the PR branch's code.
7. Debugging: inspect the real claims
The most common failure (403) is a mismatch between the configured sub/aud and what GitHub emits, especially after the format change. Instead of guessing, print only the claims (never the full token) in a test workflow:
- name: Inspect OIDC claims (debug only)
run: |
URL="${ACTIONS_ID_TOKEN_REQUEST_URL}&audience=https://infisical.example.com"
curl -sS -H "Authorization: bearer ${ACTIONS_ID_TOKEN_REQUEST_TOKEN}" "$URL" \
| jq -r '.value
| split(".")[1]
| gsub("-";"+") | gsub("_";"/")
| @base64d | fromjson
| {iss, aud, sub, repository_owner, repository_owner_id, repository_id, ref, event_name, job_workflow_ref}'
Compare the output, character by character, with the identity's policy. Remove this step when you're done.
8. Configuration variables and GitHub's Free plan
identity-id and domain aren't secrets; you can keep them in the workflow or in Actions variables. An easy-to-miss limitation: organization variables on the Free plan are only available to public repositories. On private repositories the repository selector appears empty. Alternatives: repository-level variables, literal values in the workflow, or a centralized reusable workflow / composite action that encapsulates the Infisical step and is called from the rest.
A centralized reusable workflow also enables the strongest defense: restrict job_workflow_ref so that only that audited workflow can obtain the token, even if another repository under the same owner tries to request it.
9. Trade-offs and limitations
- Availability dependency: the job needs both GitHub (IdP) and Infisical to be reachable. A static secret also depends on Infisical, but not on GitHub's JWKS.
- Per-owner surface: patterns like repo:<OWNER>@<OWNER_ID>/* assume everything under the owner is trusted. If not, scope by repository or by job_workflow_ref.
- IdP changes: the sub format changed in 2026. A policy built on exact strings is fragile to provider changes; use GitHub's preview and integration tests.
- Necessary, not sufficient: OIDC removes the static CI credential, not the risk of a compromised workflow inside the allowed perimeter. Complement it with branch protection, CODEOWNERS reviews and audit logs.
- Observability: review Infisical's audit logs to spot logins from unexpected identities or repositories.
10. Checklist
- [ ] Subject is never * or repo:*; pin the owner (and branch or environment). Never repo:<OWNER>* without a separator.
- [ ] Immutable subject (<OWNER>@<OWNER_ID>) after opting in the organization, or a repository_owner_id claim.
- [ ] main branch protected, or an environment with required reviewers.
- [ ] One identity per owner; organization role No Access; minimal project role.
- [ ] Access token TTL reduced (minutes, not days); uses and IPs bounded where possible.
- [ ] Explicit permissions: id-token: write and contents: read; action pinned by SHA.
- [ ] Universal Auth removed if unused.
- [ ] Alerting or periodic review of audit logs.
References
- GitHub Docs: OpenID Connect reference
- GitHub Changelog: Immutable subject claims for GitHub Actions OIDC tokens
- Infisical Docs: OIDC Auth
- Infisical/secrets-action
- RFC 7519: JSON Web Token (JWT)
- OpenID Connect Core 1.0
If you have a different approach to isolating owners or pinning job_workflow_ref, I'd love to read it in the comments.
@dfolloni Mas isso ja existia, inclusive open source, uso no meu hermes
Infisical/agent-vault
2 likes · 102 views
@ImLunaHey Self host, infisical/infisical on VPS, protect using Cloudflare Zero Access Tunnel. Thats like couple bucks a month.
1 like · 72 views
Are your passwords in Git in plain text? SOPS encrypts them
SOPS (Secrets OPerationS) is an open-source command-line tool for encrypting secrets in config files: it encrypts the values in YAML, JSON, ENV and INI files (and whole binary files) with age, PGP, AWS KMS, GCP KMS, Azure Key Vault, HuaweiCloud KMS or HashiCorp Vault and OpenBao, so the secrets can sit in Git next to your config.
The names stay readable and only the values are encrypted, so diffs stay useful. It's MPL 2.0 licensed and a CNCF Sandbox project.
In this video:
- What SOPS is and how it works (one data key per file, locked for each key you choose; sops edit decrypts into your editor and encrypts again when you exit)
- 3 real uses: commit encrypted secrets to Git, one .sops.yaml rules file for dev and prod keys, and passing secrets to an app with exec-env
- The catch: you manage the keys, losing every key means losing the data, names stay readable, and what to do if a key leaks
- Who it's for, an alternative, and how to try it
Three real uses:
1. Commit secrets to Git: each value is encrypted with AES-256-GCM (AES256_GCM), so a diff points to the value that changed (the sops: block's date and checksum change too). With a .gitattributes entry and git config diff.sopsdiffer.textconv "sops decrypt", git diff can show decrypted diffs to anyone who holds a key.
2. One rules file: a .sops.yaml at the repo root holds creation_rules, where path_regex picks the keys for each file, for example one age key for development files and another for production. The first matching rule wins.
3. Pass secrets to an app: sops exec-env puts the decrypted values in one child process's environment, never written to disk; sops exec-file hands the app a FIFO or a temporary file instead.
Also in the docs: --encrypted-regex to encrypt only the data and stringData values of a Kubernetes secrets file, key groups with Shamir's Secret Sharing (for example, keys from 2 of 3 groups needed to decrypt), sops updatekeys and sops rotate, and an optional audit log to PostgreSQL.
The catch: SOPS doesn't create or store your master keys. You bring age or PGP keys, a cloud key service (AWS KMS, Google Cloud KMS, Azure Key Vault and HuaweiCloud KMS are paid services of those cloud providers) or HashiCorp Vault or OpenBao. A file can be decrypted as long as one of its keys still works, so if you lose every one, the data can't be recovered: keep a backup key (the docs describe a spare PGP key kept securely for emergency decryption). Only values are encrypted: names and the file's structure stay readable, and the docs advise keeping encrypted files reasonably private. If a key leaks, remove it from .sops.yaml, run sops updatekeys, then sops rotate for a new data key, and only then change the passwords themselves. YAML anchors and top-level arrays aren't supported, and the key service connection has no authentication or encryption of its own (the docs suggest an SSH tunnel). There's no web interface or central secrets server: it's a command-line tool.
Try it (with dummy values):
Download a binary for your platform from github.com/getsops/sops/releases
age-keygen -o key.txt (age-keygen comes with age, its own tool)
sops encrypt --age "$(age-keygen -y key.txt)" --output test.enc.yaml test.yaml
export SOPS_AGE_KEY_FILE=key.txt
sops decrypt test.enc.yaml
Back up key.txt: it's your private key.
Links:
Repo: getsops/sops
Docs: getsops.io
Installation: getsops.io
age keys: getsops.io
.sops.yaml rules: getsops.io
Key management and rotation: getsops.io
exec-env and exec-file: getsops.io
Security and threat model: getsops.io
Licence (MPL 2.0): github.com/getsops/sops/blob/main/LICENSE
age: FiloSottile/age
Alternative: Infisical, Infisical/infisical
Facts checked 2026-10-20 (SOPS v3.13.3, released 2026-07-23; 23,455 GitHub stars). Started at Mozilla in 2015, a CNCF Sandbox project since 2023. An open-source option to consider, not an endorsement. Not affiliated with the SOPS project, the CNCF, Mozilla or Infisical.
Narration: AI voice.
#SOPS #SecretsManagement #DevOps
Chapters
0:00 Intro
0:14 The fix
0:27 How it works
0:42 Three real uses
1:01 The catch
1:25 Who it's for
1:35 Try it
11 views
Imposer des permissions à ses agents IA avec un proxy
Salut salut,
Pas un post habituel pour ce sub avec un long partage d'expérience sur commun on tente de limiter les périmètres d'actions nos agents dans ma boîte. C'est en réaction au post de totolitotix sur les libertés que s'accordent un LLM et la diffculté de les confiner : reddit.com
Vu le nombre de réactions sur le post original, ca pourra peut être être utile à d'autres (désolé pour le pavé pour les autres : )
Notre équipe a cherché un système pour éviter de fuiter des credentials vers les agents pour les circonscrire à leur tâche uniquement.
On a d'abord envisagé un secret manager en local qui stockerait tous les identifiants que les agents peuvent utiliser, mais la surface à nettoyer pour garantir l'absence de fuites de la part des users est trop importantes à couvrir en temps réel. On a retrouvé nos secrets éparpillés partout : navigateur, mémoire, slack. Même si on cleanait tout, les agents finiraient toujours par les retrouver à un moment ou à un autre. En plus, le secret manager ne permettait pas de visualiser simplement les droits des agents et leur activité réelle sur les bdd. Pour ceux qui veulent creuser : infisical a une solution OpenSource sympa : Infisical/agent-vault
On s'est ensuite tournés vers une couche au plus proche de la base de données et on a découvert des proxys MCP comme Query Shields : queryshield.dev, mais on n'a pas vu l'intérêt d'avoir un endpoint unique qu'on interroge en langage naturel, avec le LLM du proxy qui reconstruit une requête selon ses droits. Ca paraît à la fois overkill, gourmand en tokens (puisque chaque requête est tokenisée) et une boîte noire non sécurisée (puisque c'est le LLM qui décide quelle requête est réalisée). Finalement on s'est dit qu'il suffisait juste que le proxy renvoie une table de droits et la doc de l'API avec une description et les limites imposées pour chaque route.
Donc on est partis sur un montage open source simple avec :
• d9 en proxy : LaWebcapsule/d9 (un fork communautaire d'un produit qui s'est privatisé et que les IA manipulent très bien // dont je suis maintener //), qui génère instantanément un ensemble d'API sécurisées avec une gestion fine des permissions sur une BDD existante. Ce proxy agit comme fournisseur d'authentification des agents avec des tokens tournants. L'approche doit marcher avec toutes autres solutions du genre.
• Keycloak : keycloak/keycloak comme fournisseur d'authentification des utilisateurs réels, qui gère le SSO et rattache chaque agent à l'humain qui en est responsable et (2FA quand jugé nécessaire)
C'était plutôt simple à mettre en place avec une supervision visuelle en temps réel de chaque agent, de ses permissions et de son activité.
Quelques captures d'écran d'un projet demo pour illustrer comment ça marche.
Si vous avez des meilleures pratiques, je suis aussi preneur et ca pourra peut être en aider d'autres :)
1 point · 3 comments
Mentions
🖥️ infisical/infisical Infisical is the open source security infrastructure platform that teams use for secrets, certificates, privileged access management, and AI agent access. Infisical/infisical
Mi opinión: cifrar con SOPS o dotenvx y commitear ya es un gran salto. Un servidor se justifica si necesitas rotación. ¿Dónde guardas tus secretos hoy? Repos: Infisical/infisical getsops/sops openbao/openbao dotenvx/dotenvx
Infisical : une plateforme Open Source permettant de sécuriser les secrets, les certificats, les accès et les agents d'IA. 👉 Infisical/infisical t.co
Infisical : une plateforme Open Source permettant de sécuriser les secrets, les certificats, les accès et les agents d'IA. 👉 Infisical/infisical
Stop Storing Secrets in GitHub Actions (and the One Wildcard That Opens Your Vault to Every Repo on GitHub) CI/CD pipelines are one of the most attacked links in the software supply chain, and the usual root cause is the same: long-lived credentials stored as CI provider secrets. A CLIENT_ID/CLIENT_SECRET pasted into GitHub never expires, isn't bound to an execution context, and if it leaks (a log, a malicious fork, a compromised dependency) it is valid from anywhere. The alternative is workload identity federation: the job doesn't present a secret it holds, but a signed statement about who it is and in what context it runs. It is the same model AWS (IAM OIDC provider), GCP (Workload Identity Federation) and Azure (federated credentials) offer for their clouds. Here I apply it to a secrets manager, Infisical, and focus on what is rarely explained: the trust model, a recent GitHub change that breaks older configurations, and how to configure it without opening a hole. > All examples use placeholders (<OWNER>, <OWNER_ID>, <IDENTITY_ID>, infisical.example.com). Replace them with your own values. 1. Threat model | Threat | Static secret | Scoped OIDC | |---|---|---| | Secret leaked in logs or artifacts | Credential valid until rotated | Token lives for minutes and is bound to an audience | | Malicious workflow from a fork or PR | Can exfiltrate the secret if exposed | GitHub doesn't issue OIDC tokens to fork PRs, and the subject wouldn't match anyway | | Third-party repo that knows your URL | N/A | Real risk if the subject is loose (section 4) | | Rotation and revocation | Manual, with exposure windows | Nothing to rotate; revoke by removing the identity | | Attribution | One shared secret, no traceability | Every login is tied to a repo, branch and workflow | Assumptions: GitHub is the identity provider (IdP) and is trusted; GitHub-hosted runners are ephemeral; an attacker with write access to a protected branch is already inside the perimeter. 2. How the flow works sequenceDiagram participant J as Job (GitHub runner) participant G as GitHub OIDC IdP participant I as Infisical J->>G: 1. Request JWT (audience = A) G-->>J: 2. Signed JWT (RS256) J->>I: 3. POST /api/v1/auth/oidc-auth/login {identityId, jwt} I->>G: 4. Fetch .well-known + JWKS G-->>I: 5. Public keys Note over I: 6. Verify signature and claims (iss, aud, sub, claims) I-->>J: 7. Short-lived access token J->>I: 8. Read secrets with that token What matters: - The JWT (RFC 7519) is signed by GitHub with a key published in its JWKS. Infisical verifies the signature against that JWKS, so it must be able to reach token.actions.githubusercontent.com outbound (egress). If you self-host behind a strict firewall, that's the first place to look. - The token has a very short lifetime (minutes) and is issued on demand, per job. - The audience is chosen by whoever requests the token. It is not a secret and GitHub doesn't fix it. - Infisical's login endpoint takes identityId and jwt (application/x-www-form-urlencoded). 3. Relevant claims in GitHub's token | Claim | Example | Use | |---|---|---| | iss | https://token.actions.githubusercontent.com | Same for all of GitHub: doesn't discriminate | | aud | https://infisical.example.com | Chosen by the requester: doesn't discriminate | | sub | see section 4.2 | The main discriminator | | repository / repository_owner | <OWNER>/<REPO> / <OWNER> | Names (mutable) | | repository_id / repository_owner_id | numeric | Identifiers that don't change on rename | | ref, event_name | refs/heads/main, push | Branch and trigger | | environment | production | If the job uses a GitHub environment | | job_workflow_ref | <OWNER>/<REPO>/.github/workflows/x.yml@refs/heads/main | Which workflow (or reusable workflow) requested the token | 4. The critical point: iss and aud protect nothing The issuer is shared by every GitHub user, and aud is written by whoever requests the token. Anyone can create a repository, write a workflow and request a GitHub-signed JWT with aud = https://infisical.example.com. That token is cryptographically valid. So the only barrier between your Infisical and the rest of GitHub is the identity's claims policy, especially sub. Consequences: - Subject = * or repo:* is equivalent to opening authentication to any repository on GitHub. It's a manual confused deputy. - A broad pattern (repo:<OWNER>/*) is only acceptable if you control everything that runs under <OWNER> and who can write to it. - In Infisical, * in the Subject behaves like ** and also matches : and / (per its documentation). A pattern like repo:<OWNER>* would also match <OWNER>-other. Always put a / or @ separator right after the owner. 4.1. Names are mutable Historically sub was built from organization and repository names. If an organization was deleted or renamed and someone else registered the freed name, their sub would match your pattern (a namespace reuse attack). The OIDC spec requires sub to be locally unique and never reassigned; the old format didn't guarantee that. 4.2. GitHub's 2026 change: immutable subject (it affects your setup) GitHub introduced a default sub that includes the immutable IDs of the owner and the repository: old format: repo:octo-org/octo-repo:ref:refs/heads/main new format: repo:octo-org@123456/octo-repo@456789:ref:refs/heads/main According to GitHub's documentation and changelog: - Since July 15, 2026, new repositories use the immutable format by default, and renamed or transferred repositories move to it. - Older repositories keep the old format until you opt in at the organization or repository level (OIDC settings UI or REST API). A preview endpoint shows what the prefix will look like. - Not available on GitHub Enterprise Server. Practical consequence: a policy like repo:<OWNER>/*:ref:refs/heads/main stops matching new, renamed or transferred repositories. The symptom is a 403 on a repo that "used to work" or that you just created. Recommended setup: opt in your organizations and pin the Subject with the ID, which also closes the name-reuse attack: repo:<OWNER>@<OWNER_ID>/*:ref:refs/heads/main Get the owner's numeric ID with gh api users/<OWNER> --jq .id (works for organizations too). Alternatively, keep the old format and add a condition in Infisical's Claims (repository_owner_id = <OWNER_ID>). If you customize sub with include_claim_keys, note that in the immutable format owner_id and repo_id are always included. 4.3. Restricting by branch or environment repo:<OWNER>@<OWNER_ID>/*:ref:refs/heads/main # main branch only repo:<OWNER>@<OWNER_ID>/<REPO>@<REPO_ID>:environment:production # only jobs using the "production" environment Restricting to main only adds security if main is protected (required reviews, no direct pushes). If anyone with write access can push a workflow to main, the boundary disappears. Using environments with required reviewers adds a human approval before the job gets the token. 5. Design: one identity per owner Infisical supports one subject pattern per identity. Trying to cover several owners with one pattern forces you to widen it, and isolation is lost. The design I use: | Decision | Reason | |---|---| | One identity per owning account (organization or user) | Tight subject, blast radius limited to one owner | | Organization role No Access | The identity manages nothing at organization level | | Minimal project role (Viewer), only on the projects it needs | Least privilege: read only, no write or admin | | Remove Universal Auth if unused | Smaller surface: every active auth method is an entry point | | Treat identity-id as public data | It is an identifier, not a secret | 6. Step by step 6.1. Infisical 1. Access Control → Machine Identities → Create: name github-ci-<owner>, organization role No Access. 2. In the identity: Authentication → Add Auth Method → OIDC Auth with: | Field | Value | |---|---| | OIDC Discovery URL | https://token.actions.githubusercontent.com | | Issuer | https://token.actions.githubusercontent.com | | Subject | repo:<OWNER>@<OWNER_ID>/*:ref:refs/heads/main | | Audiences | https://infisical.example.com | | Claims (optional) | repository_owner_id = <OWNER_ID> | 3. Copy the identity's Identity ID. 4. In the project: Access Control → Machine Identities → Add identity, role Viewer. 6.2. Hardening the issued token (often skipped) Infisical's form proposes defaults meant for general use, not for CI: - Access Token TTL / Max TTL: 2592000 s (30 days) in the form. (The documentation also mentions 7200 s in the login response and doesn't explain the difference: check the effective value on your identity.) That's excessive for a CI job: reduce both to the longest job duration plus margin (for example 600–3600 s). - Access Token Max Number of Uses: 0 (unlimited). If your pipeline makes a bounded number of reads, set a maximum. - Trusted IPs: 0.0.0.0/0, ::/0 by default. GitHub-hosted runner ranges are broad and change; with self-hosted runners and a fixed IP you can restrict it. 6.3. Workflow name: release on: push: branches: [main] permissions: id-token: write # lets the job request the OIDC JWT contents: read # least privilege for everything else jobs: build: runs-on: ubuntu-latest environment: production # optional: manual approval and `environment` claim steps: - uses: actions/checkout@v4 - name: Fetch secrets from Infisical uses: Infisical/secrets-action@v1.0.12 # in production, pin the commit SHA with: method: oidc domain: https://infisical.example.com identity-id: <IDENTITY_ID> project-slug: <PROJECT_SLUG> env-slug: prod secret-path: / export-type: env # "file" writes a .env file instead Notes: - id-token: write does not grant write access to the repository; it only enables JWT issuance. Declare explicit permissions at workflow or job level so you don't depend on organization defaults. - Pin the action to a commit SHA (not a movable tag): the action itself is third-party code that receives your claims and returns secrets. - With export-type: env secrets become environment variables for later steps. Limit their scope to the step that uses them where possible. - Don't request tokens in workflows triggered by untrusted code. GitHub doesn't issue OIDC tokens to pull_request runs from forks (as reported by maintainers of widely used actions; it isn't on the main OIDC documentation page). Also avoid pull_request_target combined with the PR branch's code. 7. Debugging: inspect the real claims The most common failure (403) is a mismatch between the configured sub/aud and what GitHub emits, especially after the format change. Instead of guessing, print only the claims (never the full token) in a test workflow: - name: Inspect OIDC claims (debug only) run: | URL="${ACTIONS_ID_TOKEN_REQUEST_URL}&audience=https://infisical.example.com" curl -sS -H "Authorization: bearer ${ACTIONS_ID_TOKEN_REQUEST_TOKEN}" "$URL" \ | jq -r '.value | split(".")[1] | gsub("-";"+") | gsub("_";"/") | @base64d | fromjson | {iss, aud, sub, repository_owner, repository_owner_id, repository_id, ref, event_name, job_workflow_ref}' Compare the output, character by character, with the identity's policy. Remove this step when you're done. 8. Configuration variables and GitHub's Free plan identity-id and domain aren't secrets; you can keep them in the workflow or in Actions variables. An easy-to-miss limitation: organization variables on the Free plan are only available to public repositories. On private repositories the repository selector appears empty. Alternatives: repository-level variables, literal values in the workflow, or a centralized reusable workflow / composite action that encapsulates the Infisical step and is called from the rest. A centralized reusable workflow also enables the strongest defense: restrict job_workflow_ref so that only that audited workflow can obtain the token, even if another repository under the same owner tries to request it. 9. Trade-offs and limitations - Availability dependency: the job needs both GitHub (IdP) and Infisical to be reachable. A static secret also depends on Infisical, but not on GitHub's JWKS. - Per-owner surface: patterns like repo:<OWNER>@<OWNER_ID>/* assume everything under the owner is trusted. If not, scope by repository or by job_workflow_ref. - IdP changes: the sub format changed in 2026. A policy built on exact strings is fragile to provider changes; use GitHub's preview and integration tests. - Necessary, not sufficient: OIDC removes the static CI credential, not the risk of a compromised workflow inside the allowed perimeter. Complement it with branch protection, CODEOWNERS reviews and audit logs. - Observability: review Infisical's audit logs to spot logins from unexpected identities or repositories. 10. Checklist - [ ] Subject is never * or repo:*; pin the owner (and branch or environment). Never repo:<OWNER>* without a separator. - [ ] Immutable subject (<OWNER>@<OWNER_ID>) after opting in the organization, or a repository_owner_id claim. - [ ] main branch protected, or an environment with required reviewers. - [ ] One identity per owner; organization role No Access; minimal project role. - [ ] Access token TTL reduced (minutes, not days); uses and IPs bounded where possible. - [ ] Explicit permissions: id-token: write and contents: read; action pinned by SHA. - [ ] Universal Auth removed if unused. - [ ] Alerting or periodic review of audit logs. References - GitHub Docs: OpenID Connect reference - GitHub Changelog: Immutable subject claims for GitHub Actions OIDC tokens - Infisical Docs: OIDC Auth - Infisical/secrets-action - RFC 7519: JSON Web Token (JWT) - OpenID Connect Core 1.0 If you have a different approach to isolating owners or pinning job_workflow_ref, I'd love to read it in the comments.
@dfolloni Mas isso ja existia, inclusive open source, uso no meu hermes Infisical/agent-vault
@ImLunaHey Self host, infisical/infisical on VPS, protect using Cloudflare Zero Access Tunnel. Thats like couple bucks a month.
Are your passwords in Git in plain text? SOPS encrypts them SOPS (Secrets OPerationS) is an open-source command-line tool for encrypting secrets in config files: it encrypts the values in YAML, JSON, ENV and INI files (and whole binary files) with age, PGP, AWS KMS, GCP KMS, Azure Key Vault, HuaweiCloud KMS or HashiCorp Vault and OpenBao, so the secrets can sit in Git next to your config. The names stay readable and only the values are encrypted, so diffs stay useful. It's MPL 2.0 licensed and a CNCF Sandbox project. In this video: - What SOPS is and how it works (one data key per file, locked for each key you choose; sops edit decrypts into your editor and encrypts again when you exit) - 3 real uses: commit encrypted secrets to Git, one .sops.yaml rules file for dev and prod keys, and passing secrets to an app with exec-env - The catch: you manage the keys, losing every key means losing the data, names stay readable, and what to do if a key leaks - Who it's for, an alternative, and how to try it Three real uses: 1. Commit secrets to Git: each value is encrypted with AES-256-GCM (AES256_GCM), so a diff points to the value that changed (the sops: block's date and checksum change too). With a .gitattributes entry and git config diff.sopsdiffer.textconv "sops decrypt", git diff can show decrypted diffs to anyone who holds a key. 2. One rules file: a .sops.yaml at the repo root holds creation_rules, where path_regex picks the keys for each file, for example one age key for development files and another for production. The first matching rule wins. 3. Pass secrets to an app: sops exec-env puts the decrypted values in one child process's environment, never written to disk; sops exec-file hands the app a FIFO or a temporary file instead. Also in the docs: --encrypted-regex to encrypt only the data and stringData values of a Kubernetes secrets file, key groups with Shamir's Secret Sharing (for example, keys from 2 of 3 groups needed to decrypt), sops updatekeys and sops rotate, and an optional audit log to PostgreSQL. The catch: SOPS doesn't create or store your master keys. You bring age or PGP keys, a cloud key service (AWS KMS, Google Cloud KMS, Azure Key Vault and HuaweiCloud KMS are paid services of those cloud providers) or HashiCorp Vault or OpenBao. A file can be decrypted as long as one of its keys still works, so if you lose every one, the data can't be recovered: keep a backup key (the docs describe a spare PGP key kept securely for emergency decryption). Only values are encrypted: names and the file's structure stay readable, and the docs advise keeping encrypted files reasonably private. If a key leaks, remove it from .sops.yaml, run sops updatekeys, then sops rotate for a new data key, and only then change the passwords themselves. YAML anchors and top-level arrays aren't supported, and the key service connection has no authentication or encryption of its own (the docs suggest an SSH tunnel). There's no web interface or central secrets server: it's a command-line tool. Try it (with dummy values): Download a binary for your platform from github.com/getsops/sops/releases age-keygen -o key.txt (age-keygen comes with age, its own tool) sops encrypt --age "$(age-keygen -y key.txt)" --output test.enc.yaml test.yaml export SOPS_AGE_KEY_FILE=key.txt sops decrypt test.enc.yaml Back up key.txt: it's your private key. Links: Repo: getsops/sops Docs: getsops.io Installation: getsops.io age keys: getsops.io .sops.yaml rules: getsops.io Key management and rotation: getsops.io exec-env and exec-file: getsops.io Security and threat model: getsops.io Licence (MPL 2.0): github.com/getsops/sops/blob/main/LICENSE age: FiloSottile/age Alternative: Infisical, Infisical/infisical Facts checked 2026-10-20 (SOPS v3.13.3, released 2026-07-23; 23,455 GitHub stars). Started at Mozilla in 2015, a CNCF Sandbox project since 2023. An open-source option to consider, not an endorsement. Not affiliated with the SOPS project, the CNCF, Mozilla or Infisical. Narration: AI voice. #SOPS #SecretsManagement #DevOps Chapters 0:00 Intro 0:14 The fix 0:27 How it works 0:42 Three real uses 1:01 The catch 1:25 Who it's for 1:35 Try it
Imposer des permissions à ses agents IA avec un proxy Salut salut, Pas un post habituel pour ce sub avec un long partage d'expérience sur commun on tente de limiter les périmètres d'actions nos agents dans ma boîte. C'est en réaction au post de totolitotix sur les libertés que s'accordent un LLM et la diffculté de les confiner : reddit.com Vu le nombre de réactions sur le post original, ca pourra peut être être utile à d'autres (désolé pour le pavé pour les autres : ) Notre équipe a cherché un système pour éviter de fuiter des credentials vers les agents pour les circonscrire à leur tâche uniquement. On a d'abord envisagé un secret manager en local qui stockerait tous les identifiants que les agents peuvent utiliser, mais la surface à nettoyer pour garantir l'absence de fuites de la part des users est trop importantes à couvrir en temps réel. On a retrouvé nos secrets éparpillés partout : navigateur, mémoire, slack. Même si on cleanait tout, les agents finiraient toujours par les retrouver à un moment ou à un autre. En plus, le secret manager ne permettait pas de visualiser simplement les droits des agents et leur activité réelle sur les bdd. Pour ceux qui veulent creuser : infisical a une solution OpenSource sympa : Infisical/agent-vault On s'est ensuite tournés vers une couche au plus proche de la base de données et on a découvert des proxys MCP comme Query Shields : queryshield.dev, mais on n'a pas vu l'intérêt d'avoir un endpoint unique qu'on interroge en langage naturel, avec le LLM du proxy qui reconstruit une requête selon ses droits. Ca paraît à la fois overkill, gourmand en tokens (puisque chaque requête est tokenisée) et une boîte noire non sécurisée (puisque c'est le LLM qui décide quelle requête est réalisée). Finalement on s'est dit qu'il suffisait juste que le proxy renvoie une table de droits et la doc de l'API avec une description et les limites imposées pour chaque route. Donc on est partis sur un montage open source simple avec : • d9 en proxy : LaWebcapsule/d9 (un fork communautaire d'un produit qui s'est privatisé et que les IA manipulent très bien // dont je suis maintener //), qui génère instantanément un ensemble d'API sécurisées avec une gestion fine des permissions sur une BDD existante. Ce proxy agit comme fournisseur d'authentification des agents avec des tokens tournants. L'approche doit marcher avec toutes autres solutions du genre. • Keycloak : keycloak/keycloak comme fournisseur d'authentification des utilisateurs réels, qui gère le SSO et rattache chaque agent à l'humain qui en est responsable et (2FA quand jugé nécessaire) C'était plutôt simple à mettre en place avec une supervision visuelle en temps réel de chaque agent, de ses permissions et de son activité. Quelques captures d'écran d'un projet demo pour illustrer comment ça marche. Si vous avez des meilleures pratiques, je suis aussi preneur et ca pourra peut être en aider d'autres :)