Share via


What is SSH Posture Control?

SSH Posture Control enables you to audit and configure SSH Server security posture on supported Linux distros including Ubuntu, Red Hat, Azure Linux, and more. SSH Posture Control integrates seamlessly with Azure Governance services (Policy, Machine Configuration) so you can:

  • Ensure compliance with sshd standards in your industry or organization
  • Reduce attack surface of sshd-based remote management
  • Ensure consistent sshd setup across your fleet for security and productivity

Screenshot showing list of compliant SSH checks

To help you demonstrate compliance to auditors (and to help you take action where needed) each compliance check includes evidence via the Reasons field indicating how compliance or non-compliance was determined.

You can customize the sshd parameters (port number, allowed groups, etc.) or use the policy default values, which are aligned to the Azure security baseline for Linux.

Documentation for getting started

Selecting audit-only vs. audit-and-configure behavior

When assigning an SSH Posture Control policy, you can choose audit-only (aka "Audit") behavior or audit-and-configure (aka "Configure") behavior.

Policy definition Azure Policy effect Notes on what to expect
Audit-only behavior **Audit** SSH Posture Control on Linux machines auditIfNotExists The policy includes more restrictive settings compared to many popular system images. For example, denial of root ssh access. Accordingly, expect to see Not-compliant states reported.
Audit-and-configure behavior **Configure** SSH Posture Control on Linux machines deployIfNotExists As above, you can expect to see Not-compliant states reported initially. Subsequently, the machines will be reconfigured to match the policy, resulting in eventual Compliant states.

For existing machines, admins typically start with audit-only behavior to determine existing state and to discover dependencies such as accounts allowed for systems automation. After comparing the existing fleet against SSH Posture Control defaults, you would decide which SSH Posture Control parameters to customize. After this analysis and planning, you would then transition to audit-and-configure behavior (with safe deployment practices such as rings).

For greenfield scenarios or disposable test machines, you might choose to skip that analysis and move directly to audit-and-configure behavior, starting fresh with strong SSH Posture Control defaults.

Caution

Before configuring any machines, take great care to validate your new configuration. You could accidentally lose access to your machines.

Examples of accidentally locking yourself out include:

  • The net authorization settings applied (combination of allowUsers,denyGroups,permitRootLogin, etc.) do not allow the logins you need
  • The port you configure for sshd is blocked by other controls in your environment (SELinux policies, host firewall rules, network firewall rules, etc.)
    • Note that many Red Hat family distros have SELinux policies in place by default which block sshd from using ports other than 22.
    • To avoid overstepping enterprise team boundaries, SSH Posture Control only configured sshd. It does not currently attempt to modify on-machine SELinux policies, firewall rules, etc. to accommodate the configured sshd port. If you would like to discuss these scenarios with us, please contact us (see Additional resources below).

SSH Posture Control scope: rules, defaults, and customization

The following table lists the items that can be audited or configured with SSH Posture Control. Each of these is known as a rule.

Each rule has a default configuration value, aligned to the Azure security baseline for Linux.

Most rules can be given custom values, via policy assignment parameters to audit against or configure and audit. For example, if the standard in your organization is to use port 1111 (rather than 22) for sshd, you would set the corresponding parameter in the policy assignment. These parameters have identifiers which are included in the table below. Typically, the short parameter name is used programmatically (for example with az policy assignment create --params ...), while the longer parameter display name is used in Azure portal workflows.

When customizing values, take care to provide values which are compatible with sshd. For example, allowGroups takes a space delimited list of group name patterns. For reference, see the sshd_config man page. The sshd_config reference is also useful for understanding other sshd behaviors such as how allow and deny lists intersect.

Note

To preserve table layout, some cell values have been moved to footnotes below the table.

Rule name Default value Parameter name Parameter display name
Ensure that permissions on /etc/ssh/sshd_config are configured 600 <footnote 1> Access permissions for sshd_config
Ensure that IgnoreRhosts is set yes ignoreHosts Ignore rhosts and shosts
Ensure that LogLevel is set INFO logLevel Log verbosity level
Ensure that MaxAuthTries is set 6 maxAuthTries Maximum number of authentication attempts
Ensure that allowed users for SSH access are configured @ <see footnote 5> allowUsers Allowed users for SSH
Ensure that denied users for SSH access are configured root denyUsers Denied users for SSH
Ensure that allowed groups for SSH access are configured * allowGroups Allowed groups for SSH
Ensure that denied groups for SSH access are configured root denyGroups Denied groups for SSH
Ensure that HostbasedAuthentication is set no hostBasedAuthentication Host-based authentication
Ensure that PermitRootLogin is set no permitRootLogin Whether root can log in using ssh
Ensure that PermitEmptyPasswords is set no permitEmptyPasswords Whether the server allows login to accounts with empty password strings
Ensure that ClientAliveCountMax is set 0 clientAliveCountMax The number of client alive messages which may be sent without sshd receiving any messages back from the client
Ensure that ClientAliveInterval is set 3600 clientAliveInterval Timeout interval in seconds after which if no data has been received from the client, sshd will send a message to request a response
Ensure that MACs are configured <footnote 2> <footnote 3> The list of available message authentication code (MAC) algorithms
Ensure that a banner is configured <footnote 4> banner The contents of the banner file that is sent to the remote user before authentication is allowed
Ensure that PermitUserEnvironment is set no permitUserEnvironment Whether ~/.ssh/environment and environment= options in ~/.ssh/authorized_keys are processed by sshd
Ensure that Ciphers are configured aes128-ctr,aes192-ctr,aes256-ctr ciphers The list of allowed ciphers
Ensure that the SSH port is configured 22 port The SSH port
Ensure that the best practice protocol is used 2 <no parameter> <no parameter>

Table footnotes:

  1. accessPermissionsForSshdConfig

  2. messageAuthenticationCodeAlgorithms

  3. hmac-sha2-256,hmac-sha2-256-etm@openssh.com,hmac-sha2-512,hmac-sha2-512-etm@openssh.com

  4. #######################################################################\n\nAuthorized access only!\n\nIf you are not authorized to access or use this system, disconnect now!\n\n#######################################################################\n

    1. Note: this displays to end users as:
    #######################################################################
    
    Authorized access only!
    
    If you are not authorized to access or use this system, disconnect now!
    
    #######################################################################
    
  5. In allowUsers the default value "@" represents all accounts on the machine

Additional (non-sshd) policy parameters

These additional policy parameters are available during policy assignment. These influence Azure Policy assignment behavior, as opposed to sshd settings on machines.

Name Description Default
Include Arc connected servers By selecting this option, you agree to be charged monthly per Arc connected machine. FALSE
Effect Enable or disable the execution of this policy <Depends on Selecting audit-only vs. audit-and-configure behavior>

Policy definitions? Policy assignments? Guest assignments? Machine Configuration? How does this all fit together?

To get started with SSH Posture Control, your core action is to create a policy assignment. Your policy assignment links a policy definition (e.g., "Audit SSH Posture Control for Linux machines") to a scope (e.g., "my_factory_3_resource_group").

As you use the system, you will encounter additional resource types and terminology, as summarized in the following.

diagram showing how a policy assignment links machines to the Machine Configuration service via guest assignments

Description
Policy definition Within the Policy service, the abstract data which describes a cluster of available audit and/or configuration behaviors. For example, "Audit SSH Posture Control on Linux machines".
Policy assignment Links an abstract policy definition to a concrete scope, such as a resource group. The policy assignment can include Parameters and other properties which are specific to that assignment.
Machine Configuration The Azure service and agentry which handle auditing and setting configuration at the OS level.
Guest assignment Resource that acts as a three-way link between the policy assignment, the machine, and the Machine Configuration service. Policy creates and monitors guest assignment resources as needed.
For more information on "guest" vs. "machine" terminology, see Why do I see the terms "Guest Configuration" and "Automanage" in places?
Machine An Arc-enabled machine or an Azure VM.

About compatibility (distros, SSH Server implementations, etc.)

SSH Posture Control is designed for the mainstream general-purpose Linux scenario of a single long-running SSH Server instance:

  • whose lifecycle is managed by the init system sush as systemd
  • whose behavior is goverened by sshd_config file, consistent with OpenSSH sshd behavior
  • whose effective configuration/state is revealed by sshd -T output, consistent with OpenSSH sshd behavior

For all supported distros (see below), this is the default SSH Server use case.

In principle, a machine could have any number of SSH server instances running with varying lifetimes, based on any number of codebases, and taking their configuration from any number of places (config files, command line arguments, compile time parameters, etc.). Such cases are out of scope for SSH Posture Control at this time. If you are interested in such cases for the future, please contact us to discuss.

SSH Posture Control is intended for use on those Linux distros supported by Azure Policy and Machine Configuration-- excluding those which were in extended support at the time of development. Specifically, the following are in scope as of 2024-06-05:

  • AlmaLinux 9
  • Amazon Linux 2
  • Ubuntu Server 20.04
  • Ubuntu Server 22.04
  • Debian 10
  • Debian 11
  • Debian 12
  • Azure Linux (CBL Mariner) 2
  • Oracle Linux 7
  • Oracle Linux 8
  • CentOS 7.3
  • CentOS 8
  • RHEL 7.4
  • RHEL 8
  • RHEL 9
  • Rocky Linux 9
  • SLES 15

To the extent feasible, SSH Posture Control is tested with specific widely used system compositions of the above distros. For example, OS image compositions published by distro maintainers in the Azure gallery. Compatibility with any specific machine at run time cannot be guaranteed as sysadmins and image builders are free to remove components from the OS, make filesystems read-only, block agent actions with SELinux, etc.

Compatibility with sshd_config Include directives

SSH Posture Control attempts to accommodate and make use of Include directives in sshd_config, as follows:

  • For audit/read actions: Rely on sshd -T to reflect the net configuration from sshd's perspective-- taking into account any Includes.
  • For configure/write actions:
    • If the sshd implementation on the machine supports Includes, link a new SSH Posture Control specific file to sshd_config (as an Include). Subsequently, place all writes into the linked SSH Posture Control file. This enhances system hygiene and traceability of system changes.
    • If the sshd implementation on the machine does not support Include directives, write any configuration changes directly to sshd_config.

Compatibility with sshd_config Match directives

SSH Posture Control is designed to audit and configure core sshd behavior. It does not attempt to interact with conditional Match blocks (if any) which can apply different sshd configurations to specific populations.

Compatibility with multiple sshd_config values

SSH Posture Control does not support the use of multiple values for the rule 'port' i.e, setting the rule 'port' to 22 and 33. This rule should be configured with a single value to ensure proper functionality and compliance for auditing and configuring scenarios. Other rules such as allow/deny users and ciphers can have multiple values, as long as they are added on a single line.

Example:

  • An existing sshd_config file includes a line "port:22" and another line "port:33".
  • The "Audit SSH" Policy is used to audit for an expected port value of 33.
  • Outcome: The audit may pass or fail unpredictably.
  • Recommendation: Do not use this feature with scenarios such as these.

How can I query the results programmatically?

Using Azure Resource Graph (ARG) queries you can integrate assignment and status data into your own workflows. These examples use Search-AzGraph in PowerShell to execute the ARG query, but PowerShell is not required. You can use ARG from many entry points including the Azure Portal, Azure CLI, REST calls, etc.

  1. At the highest altitude of summarization, you can get machine counts per compliance status bucket. For example:

    $machineCountsQuery = @'
    // SSH machine counts by compliance status
    guestconfigurationresources
    | where name contains "LinuxSshServerSecurityBaseline"
    | extend complianceStatus = tostring(properties.complianceStatus)
    | summarize machineCount = count() by complianceStatus
    '@
    
    Search-AzGraph -Query $machineCountsQuery
    
    <#
    Sample output from an environment with two machines:
    
    complianceStatus machineCount
    ---------------- ------------
    Pending                     1
    Compliant                   1
    #>
    
  2. To drill in such that you see overall compliance status by machine, you can use the following:

    $machinePerRowQuery = @'
    // SSH machine level compliance
    guestconfigurationresources
    | where name contains "LinuxSshServerSecurityBaseline"
    | project 
     machine = split(properties.targetResourceId,'/')[-1],
     complianceStatus = properties.complianceStatus,
     lastComplianceStatusChecked = properties.lastComplianceStatusChecked
    '@
    
    Search-AzGraph -Query $machinePerRowQuery
    
    <#
    Sample output:
    
    machine     complianceStatus lastComplianceStatusChecked
    -------     ---------------- ---------------------------
    sshdemovm01 Compliant        2/15/2024 11:07:21 PM
    sshdemovm02 Pending          1/1/0001 12:00:00 AM
    #>
    
  3. To drill down to setting-by-setting details, you can use the following:

    $settingPerRowQuery = @'
    // SSH rule level detail
    GuestConfigurationResources
    | where name contains "LinuxSshServerSecurityBaseline"
    | project report = properties.latestAssignmentReport,
     machine = split(properties.targetResourceId,'/')[-1],
     lastComplianceStatusChecked=properties.lastComplianceStatusChecked
    | mv-expand report.resources
    | project machine,
     rule = report_resources.resourceId,
     ruleComplianceStatus = report_resources.complianceStatus,
     ruleComplianceReason = report_resources.reasons[0].phrase,
     lastComplianceStatusChecked
    '@
    
    Search-AzGraph $settingPerRowQuery
    
    <#
    Sample output:
    
    machine     rule                                                  ruleComplianceStatus     ruleComplianceReason
    -------     ---------------                                                  ------               ------
    sshdemovm01 Ensure permissions on /etc/ssh/sshd_config are configured        true            Access to '/etc/ssh/sshd_config' matches required ...
    sshdemovm01 Ensure SSH is configured to meet best practices (protocol 2)     true            'Protocol 2' is found uncommented in /etc/ssh/sshd_config
    sshdemovm01 Ensure SSH is configured to ignore rhosts                        true            The sshd service reports that 'ignorerhosts' is set to 'yes'
    sshdemovm01 Ensure SSH LogLevel is set to INFO                               true            The sshd service reports that 'loglevel' is set to 'INFO'
    sshdemovm01 Ensure SSH MaxAuthTries is configured                            true            The sshd service reports that 'maxauthtries' is set to '6'
    sshdemovm01 Ensure allowed users for SSH access are configured               true            The sshd service reports that 'allowusers' is set to '*@*'
    sshdemovm01 Ensure denied users for SSH are configured                       true            The sshd service reports that 'denyusers' is set to 'root'
    sshdemovm01 Ensure allowed groups for SSH are configured                     true            The sshd service reports that 'allowgroups' is set to '*'
    sshdemovm01 Ensure denied groups for SSH are configured                      true            The sshd service reports that 'denygroups' is set to 'root'
    sshdemovm01 Ensure SSH host-based authenticationis disabled                  true            The sshd service reports that 'hostbasedauthentication' is ...
    #>
    

Why do I see the terms "Guest Configuration" and "Automanage" in places?

The Machine Configuration service has also been known as Guest Configuration and as Automanage Machine Configuration. You may encounter these names as you interact with services and documentation. For example:

  • In the Azure Resource Graph query examples in this article, the data table is called guestconfigurationresources.
  • In the Azure portal, a useful view for observing results is called "Guest Assignments".
  • In the Azure portal, when applying the relevant VM extension to enable Machine Configuration, the extension title is "Automanage Machine Configuration".

For the purposes of SSH Posture Control, there is no meaningful distinction between "guest" and "machine". Arc-enabled machines and Azure VMs are eligible.

What are the identifiers for the built-in policy definitions?

In some cases, such as creating policy assignments with Azure CLI, it may be useful or necessary to refer to a policy definition by id rather than display name.

displayName id
Audit SSH Posture Control on Linux machines /providers/Microsoft.Authorization/policyDefinitions/a8f3e6a6-dcd2-434c-b0f7-6f309ce913b4
Configure SSH Posture Control on Linux machines /providers/Microsoft.Authorization/policyDefinitions/e22a2f03-0534-4d10-8ea0-aa25a6113233