Skip to content

Ensure that the SONiC SSH service is accessible only on the management network #2329

Description

@berendt

Problem

The generated SONiC ConfigDB does not restrict which networks can reach the
switch's SSH service (TCP/22). The management VRF is enabled and eth0 carries
the OOB management IP, but the control-plane SSH service is not locked down to
the management network — front-panel / in-band interfaces with IPs in the
default VRF can still reach it. SSH must be reachable only from the
out-of-band management network.

Goal

Generate, per switch, a SONiC control-plane ACL that permits SSH only from the
device's management/OOB network and implicitly drops SSH from everywhere else.

Proposed approach

Use SONiC control-plane ACLs handled by caclmgrd: an ACL_TABLE of
type: CTRLPLANE bound to the SSH service, plus an ACL_RULE that ACCEPTs
the management subnet. When a CTRLPLANE table binds a service, caclmgrd installs
an implicit default-drop for that service, so any source outside the permitted
rules can no longer reach SSH.

The management subnet is already available in the generator:
get_device_oob_ip(device) returns (oob_ip, prefix_len); the network is
IPv4Network(f"{oob_ip}/{prefix_len}", strict=False) — the same data used for
MGMT_INTERFACE (config_generator.py:363-369).

Only the device's own OOB management subnet is permitted; no other sources
(metalbox/gateway, central admin networks, etc.) are added in this iteration.

Example (per device, subnet derived from the OOB IP):

"ACL_TABLE": {
    "SSH_ONLY": {
        "policy_desc": "SSH_ONLY",
        "type": "CTRLPLANE",
        "services": ["SSH"]
    }
},
"ACL_RULE": {
    "SSH_ONLY|RULE_1": {
        "PRIORITY": "9999",
        "PACKET_ACTION": "ACCEPT",
        "SRC_IP": "<oob_subnet>/<prefix>",
        "IP_TYPE": "IP"
    }
}

Implementation notes

  • New helper _add_ssh_acl_configuration(config, device, oob_ip_result) in
    osism/tasks/conductor/sonic/config_generator.py, called from
    generate_sonic_config near the management-interface block, only when an OOB
    IP exists. When no OOB IP is present, no ACL is emitted (and SSH is not
    locked down — to be revisited if needed).
  • Register ACL_TABLE and ACL_RULE as generator-owned tables
    (TOP_LEVEL_SCAFFOLD_KEYS / OWNED_TABLE_KEYS) so they are rebuilt from
    scratch on every regen and never carry stale entries.
  • Permit only the local OOB subnet (oob_ip/prefix_len, normalised to the
    network address). This matches "only the management network".
  • Validation: SONiC ACL_TABLE / ACL_RULE are not yet in the generated
    pydantic schema set (_generated/_schemas.py only models DASH_ACL_*), so
    the validator emits warnings, not errors, for these tables. Consider adding
    the sonic-acl YANG model and regenerating (relates to Cover Enterprise SONiC tables in the YANG model set #2258).
  • Add unit tests under tests/unit/tasks/conductor/sonic/: ACL generated when
    OOB IP present, correct (network-normalised) subnet in the rule, table absent
    when no OOB IP.

Related

Metadata

Metadata

Assignees

Labels

No labels
No labels

Type

No type

Projects

Status
Done

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions