- Nix 100%
NixOS and Home Manager modules to run Warsaw (Guardião) natively on NixOS. Warsaw is the banking security daemon by Diebold Nixdorf required by many Brazilian banks (Itaú, Banco do Brasil, Caixa, Sicredi, and others). Key discovery: Warsaw has anti-sandbox detection — bwrap/FHS env gets r:0 (not installed), native execution gets r:1 (installed). This module uses autoPatchelfHook + activation script symlinks instead of buildFHSEnv. Includes: - Package with autoPatchelfHook for NixOS library paths - NixOS module (services.warsaw) with systemd service + activation script - Home Manager module (programs.warsaw) for browser cert trust via certutil - flake-parts consumer module - Eval checks and GitHub Actions CI Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> |
||
|---|---|---|
| .github/workflows | ||
| modules | ||
| .gitignore | ||
| checks.nix | ||
| flake.lock | ||
| flake.nix | ||
| LICENSE | ||
| package.nix | ||
| README.md | ||
warsaw-nix
NixOS and Home Manager modules to run Warsaw (Guardiao) natively on NixOS.
What is Warsaw?
Warsaw is the security module by GAS Tecnologia / Diebold Nixdorf required by many Brazilian banks for internet banking. It runs as a local daemon on port 30800/30900 and validates the browser environment before allowing access to banking websites. This flake packages Warsaw and provides declarative NixOS + Home Manager modules so it runs natively on NixOS without FHS containers or VMs.
Supported banks
Confirmed working:
- Itau
- Banco do Brasil
- Caixa Economica Federal
- Sicredi
Reported working:
- Safra
- Banese
- Banco do Nordeste
- Banco de Brasilia (BRB)
- Banco da Amazonia
Not Warsaw (different security modules):
- Bradesco -- uses its own security module
- Santander -- uses MPS (Monitor de Pagamentos Seguros)
Quick start
NixOS module
Add warsaw-nix to your flake inputs and enable the NixOS module for the system daemon, plus the Home Manager module for browser certificate trust.
# flake.nix
{
inputs = {
nixpkgs.url = "github:nixos/nixpkgs/nixos-unstable";
home-manager.url = "github:nix-community/home-manager";
warsaw-nix.url = "github:gustavobelfort/warsaw-nix";
};
outputs = { nixpkgs, home-manager, warsaw-nix, ... }: {
nixosConfigurations.myhost = nixpkgs.lib.nixosSystem {
system = "x86_64-linux";
modules = [
warsaw-nix.nixosModules.warsaw
home-manager.nixosModules.home-manager
{
# System daemon
services.warsaw.enable = true;
# Browser certificate trust (inside home-manager)
home-manager.users.youruser = {
imports = [ warsaw-nix.homeManagerModules.warsaw ];
programs.warsaw = {
enable = true;
browsers = [ "firefox" "chromium" ]; # default: [ "firefox" ]
};
};
}
];
};
};
}
flake-parts usage
If your flake uses flake-parts, import the consumer module to re-export all warsaw-nix outputs:
# flake.nix (flake-parts consumer)
{
inputs.warsaw-nix.url = "github:gustavobelfort/warsaw-nix";
outputs = inputs:
inputs.flake-parts.lib.mkFlake { inherit inputs; } {
imports = [ inputs.warsaw-nix.flakeModules.default ];
# warsaw-nix.nixosModules, homeManagerModules, and overlays
# are now available in your flake outputs.
};
}
How it works
Key discovery: anti-sandbox detection
Warsaw actively detects sandboxed environments. When run inside bwrap or an FHS container it reports r:0 (not installed) to the bank's detection JavaScript, even though the daemon is running and accepting WebSocket connections. Running natively on the host produces r:1 (installed). This is why we use autoPatchelfHook and symlinks instead of buildFHSEnv.
Architecture
-
Package (
package.nix): Fetches the official.debfrom Itau's CDN and usesautoPatchelfHookto patch ELF binaries for NixOS library paths (dbus, nss, at-spi2-atk, libXcursor, libXft). -
NixOS module (
services.warsaw): On each boot, an activation script recreates/usr/local/{bin,lib}/warsaw/as symlinks into the Nix store and points/usr/local/etc/warsawat the mutable state directory. A systemd service starts thecoredaemon as root withType=forking. -
Home Manager module (
programs.warsaw): A per-user systemd service that waits for the Warsaw daemon to generate its CA certificate (/var/lib/warsaw/rootca.crt), then injects it into Firefox and/or Chromium NSS databases usingcertutil. This allows browsers to trust the local TLS connection onwss://127.0.0.1:30900. -
Mutable state: Warsaw writes runtime data to
/var/lib/warsaw/. On impermanence systems (ephemeral root), persist this directory:environment.persistence."/nix/persist".directories = [ "/var/lib/warsaw" ];
Troubleshooting
Check the daemon is running
systemctl status warsaw
# Should show active (running), 2 core processes
Check the listening ports
ss -tlnp | grep -E '3080|3090'
# Should show:
# 127.0.0.1:30800 (HTTP WebSocket)
# 127.0.0.1:30900 (TLS WebSocket)
Test the TLS endpoint
curl --cacert /var/lib/warsaw/rootca.crt https://127.0.0.1:30900/
# Expected: HTTP 426 Upgrade Required (this confirms TLS works)
Verify in your browser
Open your bank's website. If Warsaw is running correctly, you should not see any "Install Guardiao" prompts.
Common issues
- Service fails to start: Check
journalctl -u warsawfor errors. Ensure/usr/local/bin/warsaw/coreexists (the activation script creates it). - Browser still prompts for install: The HM module may not have injected the certificate yet. Run
systemctl --user status warsaw-cert-trustand check if the cert file exists at/var/lib/warsaw/rootca.crt. - Certificate not trusted: Restart the HM service:
systemctl --user restart warsaw-cert-trust. For Chromium, ensure~/.pki/nssdbexists.
Overriding the .deb source
For airgapped environments, a local mirror, or to pin a specific version:
services.warsaw = {
enable = true;
package = warsaw-nix.packages.x86_64-linux.warsaw.overrideAttrs {
src = pkgs.fetchurl {
url = "https://your-mirror.example.com/warsaw_setup_64.deb";
sha256 = "...";
};
};
};
Or with a local .deb file:
services.warsaw = {
enable = true;
package = warsaw-nix.packages.x86_64-linux.warsaw.overrideAttrs {
src = ./warsaw_setup_64.deb;
};
};
Comparison with itau-nix (VM approach)
| warsaw-nix (native) | itau-nix (VM) | |
|---|---|---|
| Approach | Patched binaries + symlinks | Full QEMU/libvirt VM |
| Disk usage | ~30 MB | ~4 GB |
| RAM usage | ~50 MB | ~4 GB |
| Startup time | Seconds | Minutes |
| Bank compatibility | Any Warsaw-based bank | Itau only (preconfigured) |
| Sandbox detection | Passes (r:1) |
N/A (full OS) |
| Complexity | Low (2 module imports) | High (VM management) |
Security considerations
- Warsaw runs as root via a systemd service. This is required by the software.
- It listens only on localhost (127.0.0.1:30800 and 127.0.0.1:30900) — not exposed to the network.
- The binary is proprietary and closed-source. The Nix code in this repository is MIT-licensed, but Warsaw itself is distributed under Diebold Nixdorf's terms.
- The daemon generates a self-signed CA certificate and injects it into browser trust stores. This is by design -- it needs TLS for the local WebSocket connection.
- On impermanence systems,
/var/lib/warsawmust be persisted or the daemon will regenerate keys on each boot.
Contributing
PRs are welcome. To test changes locally:
# Evaluate without building
nix flake check --show-trace
# Build the package
nix build .#warsaw
# Test in a NixOS VM (if you have one configured)
sudo nixos-rebuild switch --flake .#yourhost
If you confirm Warsaw works with a bank not listed above, please open an issue or PR to update this README.
License
The Nix code in this repository is licensed under the MIT License.
Warsaw itself is proprietary software by GAS Tecnologia / Diebold Nixdorf. This project merely packages it for NixOS and does not redistribute the binary -- it is fetched directly from the official source at build time.