Generic SSH provisioning module

Tags: 300 views 0

The SSHCommand Automation Server module allows you to provision any type of service which is reachable using SSH by only configuring the resource description. The configuration contains information about how to reach the server and which commands to use for provisioning.


The intention of the SSHCommand provisioning module is to create one or more shell scripts on a server that you want to integrate into your Atomia environment. The shell scripts need to provide the functionality required to add, modify, and delete the service or services your integration consist of.

These services are configured in the Provisioning Description as handled by Atomia.Provisioning.Modules.SSHCommand.SSHCommand and can contain any properties needed to represent your use case.

The mapping of the services to a specific server and a specific set of commands is made through the Resource Description: one for add, one for modify, and one for delete.

Configuring the Provisioning Description

To specify a service to be managed through the SSHCommand provisioning module you specify a simpleService element in the Provisioning Description. See the following example from our default Provisioning Description:

<simpleService name="SomeSimpleService" friendlyName="Simple service for managing something very nice" providingModule="Atomia.Provisioning.Modules.SSHCommand.SSHCommand">
    <property name="AccountName" friendlyName="The account name of the account owning the service" />
    <property name="SomeOtherValue" friendlyName="The value to set" />

All the properties are arbitrary. You can specify any set of properties and any number of services with any name, all using this generic module.

Configuring the Resource Description

When provisioning one of the services configured to use the SSHCommand module you need to configure a resource in the Resource Description with the following set of properties:

  • ServiceName: The name property of the simpleService that you are defining the resource for.
  • Hostname: The IP or hostname of the server to start a SSH connection to when provisioning.
  • Username: The username for the SSH connection.
  • PrivateKey: A private key in PEM format (starting with —–BEGIN RSA PRIVATE KEY—–) that has passwordless access to the host.
  • ServiceName_Add: Specifies which command to use when adding the service (ServiceName should be replaced with the name of the simpleService).
  • ServiceName_Remove: Specifies which command to use when removing the service (ServiceName should be replaced with the name of the simpleService).
  • ServiceName_Modify: Specifies which command to use when modifying the service (ServiceName should be replaced with the name of the simpleService).

The following translation occurs in the properties used to specify the commands:

  • All strings of the format {{lowercasepropertyname}} are replaced by the value of the corresponding property of the simpleService. In the above simpleService example the following could be used to run a command that includes the AccountName when adding:
        <property name="SomeSimpleService_Add">echo Hello {{accountname}}</property>
  • If you need to execute multiple commands in a series (failing if one of them fails) you can use &&. Remember to quote & in the XML as &amp; or use CDATA to make the command easier to read. The following two examples are identical and similar respectively to the last example, but split into two commands and sent separately to the server:
      <property name="SomeSimpleService_Add"><![CDATA[echo Hello && echo {{accountname}}]]></property>
      <property name="SomeSimpleService_Add">echo Hello &amp;&amp; echo {{accountname}}</property>
  • For modification you can use the value of a property before the modification with {{old_lowercasepropertyname}}. See the following example:
        <property name="SomeSimpleService_Add">echo Hello former {{old_accountname}} now named {{accountname}}</property>

If you haven’t specified the corresponding property you get an exception notifying you that you are attempting something not implemented when adding, deleting, or modifying a service. If you have a valid configuration the corresponding command is executed after the translation described above. If the command returns the exit code 0 this is treated as success. Any other exit code is treated as a failure and in the exception thrown you will get the full output of the standard out and standard error streams.

Security considerations

Keep in mind

When creating the scripts (or commands) for handling the provisioning you should keep in mind that the properties can often be affected by the end user. Care has to be taken to validate and sanitize the input on the SSH server side.

The following best practices should be used when setting up the receiving end on the SSH server side:

  1. Use a separate system user for the service you want to provision.
  2. Make sure that access through this system user is not allowed with passwords.
  3. When authorizing the SSH key configured in the Resource Description in ~/.ssh/authorized_keys, restrict the command allowed to only your script. Example of an authorized_keys file:
      command="/opt/yourcompany/ $SSH_ORIGINAL_COMMAND",no-port-forwarding,no-x11-forwarding,no-agent-forwarding ssh-rsa ...base64... someuser@someserver
  4. If you use any arguments in your script, you have to make sure as the very first thing to validate that they contain nothing unexpected. If you don’t use any arguments, don’t use $SSH_ORIGINAL_COMMAND in the authorized_keys command restriction.
  5. If your script needs elevated privileges, use sudo from within the script and restrict the allowed commands for your user in the sudoer’s config to the minimum needed.

Was this helpful?