Page MenuHomeVyOS Platform

`strip_config.py`: secrets of about 80 CLI nodes are not redacted by `vyos-show-config --strip-private` and the machine-readable tech-support data
Open, LowPublic

Description

Description

python/vyos/utils/strip_config.py redacts secrets from a configuration with a hand written list of paths. It is used by vyos-show-config --strip-private and by the running configuration part of the machine-readable tech-support data (src/op_mode/tech_support.py, _get_running_config(), used by show tech-support report machine-readable). The file was added in July 2024 (T6498) and has only had formatting and license changes since, so nodes added later are not in it, and many older ones never were.

Example, VyOS rolling 2026.10.16, one committed value:

set system proxy url http://192.0.2.1
set system proxy port 3128
set system proxy username proxyuser
set system proxy password SECRETPROXYPW
commit
$ vyos-show-config --strip-private          # prints:  password "SECRETPROXYPW"
$ show configuration commands | strip-private   # prints: set system proxy password xxxxxx

_get_running_config() of tech_support.py also returns SECRETPROXYPW in clear text. (On my image show tech-support report machine-readable itself stops with NotADirectoryError: /sys/module/compression in get_module_data(), so I called the function directly. That crash is a separate problem.)

How I looked at it

I expanded the interface definitions of rolling with their includes and took every leaf node whose name looks like a secret (secret, passw*, passphrase, psk, token, key, community, md5, ...): 171 candidates. After removing obvious non-secrets (key-name, secret-length, password-protected, public-key, key-exchange, GRE tunnel keys and similar) and two nodes that only name a PKI object or a file (protocols rpki cache ssh key, service dns dynamic name key) 80 remain, plus 8 copies below vrf name. For each of them I built a configuration tree with a marker value, ran strip_config_tree() and the strip-private.py filter on a VyOS VM and checked whether the marker is still readable. As a positive control five covered paths (SNMPv3 auth, WireGuard private key, IPsec PSK, BGP neighbour password, login password hash) were all redacted.

Result: strip_config.py leaves all 88 readable. The regex filter behind | strip-private removes most of them and leaves 22 readable, plus 4 of the VRF copies (column below, for example the OpenVPN keys, WPA and eapol passphrases, WireGuard preshared-key, IPsec x509 and RSA passphrases, SNMP trap community, and the MD5 keys of IS-IS and OpenFabric).

The list is based on node names, so it needs a review by someone who knows the nodes. Some entries may not be secrets in the sense of the filter (for example the SNMP community or the MaxMind license key), I included them because they work as a credential.

Documentation

The documentation tells users to use the filter before sharing a configuration: docs/cli.md: "Use the show configuration commands | strip-private command when you want to hide private data. You may want to do so if you want to share your configuration on the forum." and docs/configuration/system/syslog.md for logs. Nothing says which values are removed or that the list is incomplete. The human readable show tech-support report and the archive are not part of this: their help text says "(contains private information)" and their running configuration sections are not redacted by design (show_techsupport_report.py, measured in the archive). The tech-support documentation (docs/vpp/troubleshooting.md) does not mention redaction at all.

Affected nodes (not redacted by strip_config.py)

NodeDefinition filePipe filter `\strip-private`
container registry <name> authentication passwordcontainer.xml.instripped
firewall global-options geoip maxmind-license-keyfirewall.xml.innot stripped
interfaces bonding <name> eapol passphraseinterfaces_bonding.xml.innot stripped
interfaces ethernet <name> eapol passphraseinterfaces_ethernet.xml.innot stripped
interfaces macsec <name> security static keyinterfaces_macsec.xml.instripped
interfaces macsec <name> security static peer <name> keyinterfaces_macsec.xml.instripped
interfaces openvpn <name> authentication passwordinterfaces_openvpn.xml.instripped
interfaces openvpn <name> shared-secret-keyinterfaces_openvpn.xml.innot stripped
interfaces openvpn <name> tls auth-keyinterfaces_openvpn.xml.innot stripped
interfaces openvpn <name> tls crypt-keyinterfaces_openvpn.xml.innot stripped
interfaces pppoe <name> authentication passwordinterfaces_pppoe.xml.instripped
interfaces sstpc <name> authentication passwordinterfaces_sstpc.xml.instripped
interfaces wireguard <name> peer <name> preshared-keyinterfaces_wireguard.xml.innot stripped
interfaces wireless <name> security wep keyinterfaces_wireless.xml.instripped
interfaces wireless <name> security wpa passphraseinterfaces_wireless.xml.innot stripped
interfaces wireless <name> security wpa radius server <name> keyinterfaces_wireless.xml.instripped
interfaces wwan <name> authentication passwordinterfaces_wwan.xml.instripped
protocols isis area-password md5protocols_isis.xml.innot stripped
protocols isis domain-password md5protocols_isis.xml.innot stripped
protocols isis domain-password plaintext-passwordprotocols_isis.xml.innot stripped
protocols isis interface <name> password md5protocols_isis.xml.innot stripped
protocols mpls ldp neighbor <name> passwordprotocols_mpls.xml.instripped
protocols openfabric domain <name> domain-password md5protocols_openfabric.xml.innot stripped
protocols openfabric domain <name> domain-password plaintext-passwordprotocols_openfabric.xml.innot stripped
protocols openfabric domain <name> interface <name> password md5protocols_openfabric.xml.innot stripped
protocols openfabric domain <name> interface <name> password plaintext-passwordprotocols_openfabric.xml.innot stripped
protocols ospf area <name> virtual-link <name> authentication md5 key-id <name> md5-keyprotocols_ospf.xml.instripped
protocols ospf area <name> virtual-link <name> authentication plaintext-passwordprotocols_ospf.xml.instripped
protocols rip interface <name> authentication md5 <name> passwordprotocols_rip.xml.instripped
service config-sync secondary keyservice_config-sync.xml.instripped
service dhcp-server dynamic-dns-update tsig-key <name> secretservice_dhcp-server.xml.instripped
service dns dynamic name <name> passwordservice_dns_dynamic.xml.instripped
service ipoe-server authentication radius dynamic-author keyservice_ipoe-server.xml.instripped
service monitoring telegraf loki authentication passwordservice_monitoring_telegraf.xml.instripped
service monitoring zabbix-agent authentication psk secretservice_monitoring_zabbix-agent.xml.instripped
service pppoe-server authentication radius dynamic-author keyservice_pppoe-server.xml.instripped
service pppoe-server ppp-options ipv6-peer-interface-id-secretservice_pppoe-server.xml.instripped
service snmp trap-target <name> communityservice_snmp.xml.innot stripped
service snmp v3 trap-target <name> auth encrypted-passwordservice_snmp.xml.instripped
service snmp v3 trap-target <name> auth plaintext-passwordservice_snmp.xml.instripped
service snmp v3 trap-target <name> privacy encrypted-passwordservice_snmp.xml.instripped
service snmp v3 trap-target <name> privacy plaintext-passwordservice_snmp.xml.instripped
service snmp v3 user <name> auth plaintext-passwordservice_snmp.xml.instripped
service stunnel client <name> options passwordservice_stunnel.xml.instripped
service stunnel client <name> psk <name> secretservice_stunnel.xml.instripped
service stunnel server <name> psk <name> secretservice_stunnel.xml.instripped
service webproxy authentication ldap passwordservice_webproxy.xml.instripped
system config-management commit-archive location <name> ftp authentication passwordsystem_config-management.xml.instripped
system config-management commit-archive location <name> ftps authentication passwordsystem_config-management.xml.instripped
system config-management commit-archive location <name> git authentication passwordsystem_config-management.xml.instripped
system config-management commit-archive location <name> http authentication passwordsystem_config-management.xml.instripped
system config-management commit-archive location <name> https authentication passwordsystem_config-management.xml.instripped
system config-management commit-archive location <name> scp authentication passwordsystem_config-management.xml.instripped
system config-management commit-archive location <name> sftp authentication passwordsystem_config-management.xml.instripped
system config-management commit-archive location <name> ssh authentication passwordsystem_config-management.xml.instripped
system login radius server <name> keysystem_login.xml.instripped
system login tacacs server <name> keysystem_login.xml.instripped
system login user <name> authentication otp keysystem_login.xml.instripped
system login user <name> authentication plaintext-passwordsystem_login.xml.instripped
system proxy passwordsystem_proxy.xml.instripped
vpn ipsec authentication ppk <name> secretvpn_ipsec.xml.instripped
vpn ipsec profile <name> authentication pre-shared-secretvpn_ipsec.xml.instripped
vpn ipsec remote-access connection <name> authentication x509 passphrasevpn_ipsec.xml.innot stripped
vpn ipsec remote-access radius server <name> keyvpn_ipsec.xml.instripped
vpn ipsec site-to-site peer <name> authentication rsa passphrasevpn_ipsec.xml.innot stripped
vpn ipsec site-to-site peer <name> authentication x509 passphrasevpn_ipsec.xml.innot stripped
vpn l2tp remote-access authentication radius dynamic-author keyvpn_l2tp.xml.instripped
vpn l2tp remote-access authentication radius server <name> keyvpn_l2tp.xml.instripped
vpn l2tp remote-access ipsec-settings authentication x509 passphrasevpn_l2tp.xml.innot stripped
vpn l2tp remote-access lns shared-secretvpn_l2tp.xml.instripped
vpn l2tp remote-access ppp-options ipv6-peer-interface-id-secretvpn_l2tp.xml.instripped
vpn openconnect accounting radius server <name> keyvpn_openconnect.xml.instripped
vpn openconnect authentication local-users username <name> otp keyvpn_openconnect.xml.instripped
vpn openconnect ssl passphrasevpn_openconnect.xml.innot stripped
vpn pptp remote-access authentication radius dynamic-author keyvpn_pptp.xml.instripped
vpn pptp remote-access authentication radius server <name> keyvpn_pptp.xml.instripped
vpn pptp remote-access ppp-options ipv6-peer-interface-id-secretvpn_pptp.xml.instripped
vpn sstp authentication local-users username <name> passwordvpn_sstp.xml.instripped
vpn sstp authentication radius dynamic-author keyvpn_sstp.xml.instripped
vpn sstp ppp-options ipv6-peer-interface-id-secretvpn_sstp.xml.instripped

Further findings while checking

  • show configuration json | strip-private and show configuration json pretty | strip-private leave the proxy password readable (the text formats show configuration and show configuration commands are stripped). The filter does not report anything, so it looks as if it worked.
  • SNMP community strings stay readable in both filters, the community name of service snmp community <name> (a tag node value, which a list of leaf paths cannot strip) as well as trap-target ... community.
  • RADIUS shared secrets are meant to be covered: the list already has the authentication radius server key of SSTP, L2TP, PPTP, OpenConnect, IPoE and PPPoE. The nodes in the table below are the ones it misses (login RADIUS and TACACS, IPsec remote-access, OpenConnect accounting, the dynamic-author keys, wireless).
  • The regex filter has a stated constraint: T5713 (2023) narrowed the secret rule because the output of strip-private must stay a valid configuration (use-secret foo became secret xxxxxx). A path based list keeps that property, a name based regex does not.
  • The two implementations have separate histories: the regex filter strip-private.py since 2021 (T3354, extended in T3642, T3926, T4177, T5713), the path list since 2024 (T6498). I found no statement which one is the reference.

Possible directions

  1. Add the nodes above to the list (a first step, mechanical).
  2. Stop maintaining the list by hand: derive the secret nodes from the definitions (for example a marker on the node) or make a unit test fail when a node whose name looks like a secret is neither in the list nor explicitly excluded.
  3. Decide which of the two filters is the reference and make the other one use the same list.

Questions for the maintainers: is the SNMP community meant to be redacted, and the MaxMind license key? Should | strip-private also work for JSON output, or refuse it?

Not checked

Logs, the other files of the archive, the nodes whose name does not look like a secret, the machine-readable tech-support command end to end (it stops on my image, see above), and behaviour on other versions.

Details

Version
rolling
Is it a breaking change?
Unspecified (possibly destroys the router)
Issue type
Unspecified (please specify)