External sources

The external sources feature enables integration with third-party applications and services. It allows for the delegation of device authentication and/or administrative authentication, such as external secret storage or third-party admin authentication methods.

There are two types of authentication:

  • Admin Authentication: used by RADKit Service to authenticate RADKit administrators (e.g at the RADKit WebUI logon).

  • Device Authentication: used by RADKit Service to authenticate to network devices.

The purpose of Admin external sources is to allow for the authentication of RADKit administrators to be delegated to the company credentials management system.

The purposes of Device external sources is to detach the credentials to a device from the main RADKit device definition. This separation allows for the credentials to be stored in

  • a secure location, such as a secrets management system (Vault, TACACS+ server, …), or

  • a central place, in the RADKit database in order to minimize the effort of updating all credentials at once.

Warning

Currently, the configuration of external sources is exclusively available through the Service WebUI and is accessible solely to the superadmin user role. To manage external sources, navigate to the External Sources tab where you can add, edit, or remove configurations.

Admin authentication

When an administrator is defined on an external source, prefix the admin username with the external source name and a hash symbol: <name_of_external_source>#<admin_user>.

As for now only TACACS+ and plugins are capable of admin authentication:

TACACS+

Plugin

Remote user authentication and authorization

In order to authenticate and authorize remote users using external source you need to:

  • Configure external source capable of authenticating and authorizing remote users.

  • Enable remote user authentication via service.ui.remote_user_external_auth_enabled setting

  • Select external source in remote user add/update window in Authentication section

    Note

    If username will be not provided user email will be used for external source authentication and authorization

    ../_images/external_sources_remote_user_auth.png

Device authentication

Device authentication details are covered in Device Templates.

CyberArk AIM CCP

Note

This section is a work in progress.

CyberArk Conjur

Note

This section is a work in progress.

Static Credentials

Note

This section is a work in progress.

Static credentials is useful when many devices share the same credentials. The device definition can refer to the external source of type Static Credentials, which stores the credentials in an encrypted form in the RADKit database.

When credentials need to be updated, only the Static Credentials definition needs to be updated, and all referring devices will automatically use the new credentials.

The statc credentials can be configured by referencing the external source in the YAML configuration:

terminal:
    external_source:
        name: <name_of_external_source>

Static credentials external source also allows for secret retrieval, which can be specified in the YAML configuration as follows:

terminal:
    password:
        external_source: <name_of_external_source>
        path: password
    username:
        external_source: <name_of_external_source>
        path: username

HashiCorp Vault

Integrating HashiCorp Vault with RADKit allows you to securely access your secrets.

Here is how you can get started:

../_images/external_sources_hashicorp_vault.png

Configuration Steps

  1. Base URL: Provide the base URL of your HashiCorp Vault server. This is the primary endpoint for API interactions. Ensure the URL is correct and accessible from your network.

  2. Secret Engine: Select the secret engine type you want to use:

    • Cubbyhole: Used for storing secrets in a private, per-client space.

    • KV v1: The first version of HashiCorp Vault’s key-value store.

    • KV v2: An enhanced version of the key-value store with support for versioning.

  3. Engine Path: Specify the path for the secret engine. This is the location within the Vault where your secrets are stored. Default paths are available based on the selected secret engine:

    • Cubbyhole: Defaults to /cubbyhole/

    • KV v1 and KV v2: Defaults to /secret/

  4. Auth Method: Choose the authentication method for accessing Vault:

    • Token: Use a pre-generated token for authentication. This method is straightforward and requires a token with appropriate permissions.

    • AppRole: Use an AppRole to authenticate. This method involves providing a Role ID and a Secret ID.

  5. Auth Path: Enter the path for authentication. This path is used to authenticate the client against the Vault server. Default paths are set based on the chosen authentication method:

    • Token: Defaults to /token/

    • AppRole: Defaults to /approle/

  6. Token/Role ID/Secret ID:

    • If using Token authentication, provide the token value.

    • If using AppRole authentication, provide the Role ID and Secret ID.

  7. Verify TLS Certificate: Check this option if you want to verify the Vault server’s TLS certificate. It’s recommended to enable this in production environments to ensure secure communication.

  8. Use Insecure TLS Algorithms: Enable this option if your Vault server requires support for outdated or insecure TLS algorithms. Use this option with caution.

Note

Ensure that the Vault server is configured with the necessary policies and permissions to allow the RADKit Service to access the required secrets

Usage

To retrieve a specific secret from HashiCorp Vault, reference the external source by name in the YAML configuration, including the secret’s path:

terminal:
    password:
        external_source: <name_of_external_source>
        path: <secret_path/key>

Plugin

This external source type allows the integration of third-party external source implementations. Plugins are added by installing plugin packages that will be visible during the configuration.

Plugin package

Plugin packages are Python packages that uses metadata for plugins through entrypoints. The plugin package needs to register classes as a entrypoints for radkit_service.external_sources.plugins group.

Examples:

  • pyproject.toml

[project.entry-points."radkit_service.external_sources.plugins"]
"My Custom Plugin" = "my_package.my_module:MyClass"
  • setup.py

from setuptools import setup

setup(
    ...,
    entry_points={
        "radkit_service.external_sources.plugins": [
            "My Custom Plugin = my_package.my_module:MyClass",
        ],
    },
)
  • config.cfg

[options.entry_points]
radkit_service.external_sources.plugins =
    My Custom Plugin = my_package.my_module:MyClass

Protocol

To fulfill the protocol’s needs, the configured implementation must follow the defined protocol:

class radkit_service.external_sources.ExternalSource

Bases: Protocol

External Source Protocol definition.

There are four methods for utilizing external sources:

  • Generating terminal/netconf/snmp/swagger/http connection parameters:

    In this method, within the YAML protocol definitions, the external source is cited in the protocol section, for example:

    terminal:
        external_source:
            name: <name of referenced external source>
            params: <additional parameters for external source>
    

    Here, the external source is tasked with constructing the TerminalConnectionParameters data structure, triggering the invocation of create_terminal_connection_parameters.

  • Retrieving secret attributes:

    In this method, within the YAML protocol definitions, the external source is mentioned in the attribute definition, for instance:

    terminal:
        password:
            external_source: <name of referenced external source>
            path: <secret path>
    

    This indicates that the external source is accountable for procuring the specific secret, and fetch_secret will be executed as below:

    await external_source.fetch_secret(path=<secret path>)
    
  • Authenticating users:

    In this method external source will be used for authenticating admins for login or authentication remote users for RPC calls. Passed username and password will be passed like this:

    await external_source.authenticate_user(
        username=<username>,
        password=<password>,
    )
    
  • Authorizing users

    In this method external source will be used for authorizing remote user for RPC calls.

    Passed username will be passed like this:

    await external_source.authorize_user(username=<username>)
    

    Returned authorized user data structure is used downstream to accept or reject specific connection. If None is returned, it means that user is not authorized.

    Note

    As for now, we are unable to do direct SSO connections if external source is used for remote user authentication and authorization.

Should a particular external source implementation be incapable of generating connection parameters or retrieving secrets, it ought to return a NotImplementedError.

Warning

Implementing a cache mechanism might provide some performance improvements, but long TTLs can reduce reactivity for changes. For example, caching authentication results can lead to a situation where a non-authorized user might be authenticated due to the cache.

async create_terminal_connection_parameters(
external_source_terminal: ExternalSourceTerminal,
) TerminalConnectionParameters | None

Creates terminal connection parameters out of External Source Terminal definition.

async create_netconf_connection_parameters(
external_source_netconf: ExternalSourceNetconf,
) NetconfConnectionParameters | None

Creates netconf connection parameters out of External Source Netconf definition.

async create_snmp_connection_parameters(
external_source_snmp: ExternalSourceSnmp,
) SNMPConnectionParameters | None

Creates snmp connection parameters out of External Source SNMP definition.

async create_swagger_connection_parameters(
external_source_swagger: ExternalSourceSwagger,
) SwaggerConnectionParameters | None

Creates swagger connection parameters out of External Source Swagger definition.

async create_http_connection_parameters(
external_source_http: ExternalSourceHttp,
) HTTPConnectionParameters | None

Creates http connection parameters out of External Source HTTP definition.

async fetch_secret(
path: str,
) str

Fetch secret for given path.

async authenticate_user(
username: str,
password: str,
) AuthenticatedUser | None

Authenticates user by given credentials.

async authorize_user(
username: str,
) AuthorizedUser | None

Authorizes user.

Data types

pydantic model radkit_service.database.models.DbExternalSourceTerminal

Bases: _NestedModel

field external_source: DbExternalSourceReference | None = None
field port: int | TemplateStr = 22
field connection_method: Literal[ConnectionMethod.SSH, ConnectionMethod.TELNET, ConnectionMethod.SSHPUBKEY, ConnectionMethod.TELNET_NO_AUTH] | TemplateStr [Required]
Validated by:
  • _validate_connection_method

field use_insecure_algorithms: bool | TemplateStr = False
field jumphost: bool | TemplateStr = False
field use_tunneling_if_jumphost: bool | TemplateStr = True
field provisioning_variant: ProvisioningVariant | TemplateStr = ProvisioningVariant.DEFAULT
field capabilities: frozenset[TerminalCapabilities | TemplateStr] = frozenset({TerminalCapabilities.DOWNLOAD, TerminalCapabilities.EXEC, TerminalCapabilities.INTERACTIVE, TerminalCapabilities.UPLOAD})
field username: DbExternalSourceSecret | DbExternalSourceValue | None = None
field password: DbExternalSourceSecret | None = None
field enable_password: DbExternalSourceSecret | None = None
field private_key: DbExternalSourceSecret | None = None
pydantic model radkit_service.database.models.DbExternalSourceNetconf

Bases: _NestedModel

field external_source: DbExternalSourceReference | None = None
field port: int | TemplateStr = 830
field use_insecure_algorithms: bool | TemplateStr = False
field username: DbExternalSourceSecret | DbExternalSourceValue | None = None
field password: DbExternalSourceSecret | None = None
pydantic model radkit_service.database.models.DbExternalSourceSnmp

Bases: _NestedModel

field external_source: DbExternalSourceReference | None = None
field version: int | TemplateStr [Required]
Constraints:
  • ge = 1

  • le = 2

field port: int | TemplateStr [Required]
field community_string: DbExternalSourceSecret | None = None
pydantic model radkit_service.database.models.DbExternalSourceSwagger

Bases: _NestedModel

field external_source: DbExternalSourceReference | None = None
field port: int | TemplateStr = 443
field schema_path: TemplateStr | str = ''
field verify: bool | TemplateStr [Required]
field use_insecure_algorithms: bool | TemplateStr = False
field username: DbExternalSourceSecret | DbExternalSourceValue | None = None
field password: DbExternalSourceSecret | None = None
pydantic model radkit_service.database.models.DbExternalSourceHttp

Bases: _NestedModel

field external_source: DbExternalSourceReference | None = None
field port: int | TemplateStr [Required]
field protocol: HTTPProtocol | TemplateStr [Required]
field verify: bool | TemplateStr [Required]
field use_insecure_algorithms: bool | TemplateStr = False
field authentication_extra: TemplateStr | str | None = None
field username: DbExternalSourceSecret | DbExternalSourceValue | None = None
field password: DbExternalSourceSecret | None = None
class radkit_service.external_sources.types.AuthenticatedUser

Bases: TypedDict

Data structure used to describe authenticated user. Used in webserver session middleware.

username: str
email: str
fullname: str
description: str
class radkit_service.external_sources.types.AuthorizedUser

Bases: TypedDict

Data structure used to describe authorized user. Used in database device backend.

connection_mode_cloud_active: bool
connection_mode_direct_active: bool
connection_mode_direct_sso_active: bool
class radkit_service.external_sources.types.TerminalConnectionParameters

Bases: TypedDict

username: str
password: str
port: int
connection_method: ConnectionMethod | str
enable_password: str
enable_set: bool
use_insecure_algorithms: bool
private_key: str
use_tunneling_if_jumphost: bool
ssh_client_parameters: SSHClientParameters | None
provisioning_variant: ProvisioningVariant | str
capabilities: Collection[TerminalCapabilities | str]
class radkit_service.external_sources.types.NetconfConnectionParameters

Bases: TypedDict

username: str
password: str
port: int
use_insecure_algorithms: bool
class radkit_service.external_sources.types.SwaggerConnectionParameters

Bases: TypedDict

username: str
password: str
verify: bool
use_insecure_algorithms: bool
schema_path: str
port: int
class radkit_service.external_sources.types.SNMPConnectionParameters

Bases: TypedDict

version: int
community_string: str
port: int
class radkit_service.external_sources.types.HTTPConnectionParameters

Bases: TypedDict

username: str
password: str
port: int
protocol: HTTPProtocol | str
verify: bool
use_insecure_algorithms: bool
authentication_extra: str | None
class radkit_common.types.ConnectionMethod

Bases: str, Enum

SSH = 'SSH'
SSHPUBKEY = 'SSHPUBKEY'
TELNET = 'TELNET'
TELNET_NO_AUTH = 'TELNET_NO_AUTH'
NETCONF = 'NETCONF'
class radkit_common.types.TerminalCapabilities

Bases: str, Enum

INTERACTIVE = 'INTERACTIVE'
EXEC = 'EXEC'
UPLOAD = 'UPLOAD'
DOWNLOAD = 'DOWNLOAD'
class radkit_common.terminal_interaction.provisioning_variants.ProvisioningVariant

Bases: str, Enum

DEFAULT = 'DEFAULT'
NCS_2000_LF1 = 'LF1'
class radkit_service.external_sources.types.SSHClientParameters

Bases: TypedDict

Class stores all of the parameters that controls behavior for SSH protocol.

keyboard_interactive_auth_requested_cb: KeyboardInteractiveAuthRequestCb | None
keyboard_interactive_challenge_received_cb: KeyboardInteractiveChallengeReceivedCb | None