opensipscli 0.4.1__tar.gz → 0.4.2__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {opensipscli-0.4.1 → opensipscli-0.4.2}/.github/workflows/pypi.yml +1 -1
- {opensipscli-0.4.1 → opensipscli-0.4.2}/PKG-INFO +1 -1
- {opensipscli-0.4.1 → opensipscli-0.4.2}/docs/modules/mi.md +6 -1
- opensipscli-0.4.2/docs/modules/tls.md +191 -0
- {opensipscli-0.4.1 → opensipscli-0.4.2}/opensipscli/cli.py +10 -3
- {opensipscli-0.4.1 → opensipscli-0.4.2}/opensipscli/db.py +13 -2
- {opensipscli-0.4.1 → opensipscli-0.4.2}/opensipscli/modules/mi.py +29 -3
- {opensipscli-0.4.1 → opensipscli-0.4.2}/opensipscli/modules/tls.py +337 -0
- {opensipscli-0.4.1 → opensipscli-0.4.2}/opensipscli/version.py +1 -1
- {opensipscli-0.4.1 → opensipscli-0.4.2}/packaging/debian/changelog +6 -0
- {opensipscli-0.4.1 → opensipscli-0.4.2}/packaging/redhat_fedora/opensips-cli.spec +3 -1
- {opensipscli-0.4.1 → opensipscli-0.4.2}/test/alltests.py +12 -0
- opensipscli-0.4.1/docs/modules/tls.md +0 -99
- {opensipscli-0.4.1 → opensipscli-0.4.2}/.github/workflows/docker-push-image.yml +0 -0
- {opensipscli-0.4.1 → opensipscli-0.4.2}/.github/workflows/docker-readme.yml +0 -0
- {opensipscli-0.4.1 → opensipscli-0.4.2}/.gitignore +0 -0
- {opensipscli-0.4.1 → opensipscli-0.4.2}/LICENSE +0 -0
- {opensipscli-0.4.1 → opensipscli-0.4.2}/README.md +0 -0
- {opensipscli-0.4.1 → opensipscli-0.4.2}/SECURITY.md +0 -0
- {opensipscli-0.4.1 → opensipscli-0.4.2}/bin/opensips-cli +0 -0
- {opensipscli-0.4.1 → opensipscli-0.4.2}/docker/Dockerfile +0 -0
- {opensipscli-0.4.1 → opensipscli-0.4.2}/docker/Makefile +0 -0
- {opensipscli-0.4.1 → opensipscli-0.4.2}/docker/docker.md +0 -0
- {opensipscli-0.4.1 → opensipscli-0.4.2}/docker/run.sh +0 -0
- {opensipscli-0.4.1 → opensipscli-0.4.2}/docs/INSTALLATION.md +0 -0
- {opensipscli-0.4.1 → opensipscli-0.4.2}/docs/modules/database.md +0 -0
- {opensipscli-0.4.1 → opensipscli-0.4.2}/docs/modules/diagnose.md +0 -0
- {opensipscli-0.4.1 → opensipscli-0.4.2}/docs/modules/instance.md +0 -0
- {opensipscli-0.4.1 → opensipscli-0.4.2}/docs/modules/trace.md +0 -0
- {opensipscli-0.4.1 → opensipscli-0.4.2}/docs/modules/trap.md +0 -0
- {opensipscli-0.4.1 → opensipscli-0.4.2}/docs/modules/user.md +0 -0
- {opensipscli-0.4.1 → opensipscli-0.4.2}/etc/default.cfg +0 -0
- {opensipscli-0.4.1 → opensipscli-0.4.2}/opensipscli/__init__.py +0 -0
- {opensipscli-0.4.1 → opensipscli-0.4.2}/opensipscli/args.py +0 -0
- {opensipscli-0.4.1 → opensipscli-0.4.2}/opensipscli/comm.py +0 -0
- {opensipscli-0.4.1 → opensipscli-0.4.2}/opensipscli/config.py +0 -0
- {opensipscli-0.4.1 → opensipscli-0.4.2}/opensipscli/defaults.py +0 -0
- {opensipscli-0.4.1 → opensipscli-0.4.2}/opensipscli/libs/__init__.py +0 -0
- {opensipscli-0.4.1 → opensipscli-0.4.2}/opensipscli/libs/sqlalchemy_utils.py +0 -0
- {opensipscli-0.4.1 → opensipscli-0.4.2}/opensipscli/logger.py +0 -0
- {opensipscli-0.4.1 → opensipscli-0.4.2}/opensipscli/main.py +0 -0
- {opensipscli-0.4.1 → opensipscli-0.4.2}/opensipscli/module.py +0 -0
- {opensipscli-0.4.1 → opensipscli-0.4.2}/opensipscli/modules/__init__.py +0 -0
- {opensipscli-0.4.1 → opensipscli-0.4.2}/opensipscli/modules/database.py +0 -0
- {opensipscli-0.4.1 → opensipscli-0.4.2}/opensipscli/modules/diagnose.py +0 -0
- {opensipscli-0.4.1 → opensipscli-0.4.2}/opensipscli/modules/instance.py +0 -0
- {opensipscli-0.4.1 → opensipscli-0.4.2}/opensipscli/modules/trace.py +0 -0
- {opensipscli-0.4.1 → opensipscli-0.4.2}/opensipscli/modules/trap.py +0 -0
- {opensipscli-0.4.1 → opensipscli-0.4.2}/opensipscli/modules/user.py +0 -0
- {opensipscli-0.4.1 → opensipscli-0.4.2}/packaging/debian/.gitignore +0 -0
- {opensipscli-0.4.1 → opensipscli-0.4.2}/packaging/debian/compat +0 -0
- {opensipscli-0.4.1 → opensipscli-0.4.2}/packaging/debian/control +0 -0
- {opensipscli-0.4.1 → opensipscli-0.4.2}/packaging/debian/copyright +0 -0
- {opensipscli-0.4.1 → opensipscli-0.4.2}/packaging/debian/rules +0 -0
- {opensipscli-0.4.1 → opensipscli-0.4.2}/packaging/debian/source/format +0 -0
- {opensipscli-0.4.1 → opensipscli-0.4.2}/packaging/debian/watch +0 -0
- {opensipscli-0.4.1 → opensipscli-0.4.2}/pyproject.toml +0 -0
- {opensipscli-0.4.1 → opensipscli-0.4.2}/setup.cfg +0 -0
- {opensipscli-0.4.1 → opensipscli-0.4.2}/setup.py +0 -0
- {opensipscli-0.4.1 → opensipscli-0.4.2}/test/test-database.sh +0 -0
- {opensipscli-0.4.1 → opensipscli-0.4.2}/test/test.sh +0 -0
|
@@ -7,9 +7,14 @@ commands and display the result in the console.
|
|
|
7
7
|
|
|
8
8
|
This module exports all the commands that are exported by the OpenSIPS
|
|
9
9
|
instance that `opensips-cli` points to. It fetches the available commands by
|
|
10
|
-
running the OpenSIPS MI `which` command.
|
|
10
|
+
running the OpenSIPS MI `which` command. It also loads MI aliases using the
|
|
11
|
+
`which_aliases` command. When running a command, it returns
|
|
11
12
|
the raw, unprocessed data from OpenSIPS.
|
|
12
13
|
|
|
14
|
+
Aliases are accepted when executing commands, but are not included in command
|
|
15
|
+
completion suggestions. Ambiguous aliases are ignored and must be invoked by
|
|
16
|
+
their canonical command name.
|
|
17
|
+
|
|
13
18
|
Commands using this module can be run in two manners:
|
|
14
19
|
* using *positional* parameters: this is similar to the old way the
|
|
15
20
|
`opensipsctl` tool was working: the parameters passed to the function are
|
|
@@ -0,0 +1,191 @@
|
|
|
1
|
+
# OpenSIPS CLI - TLS module
|
|
2
|
+
|
|
3
|
+
Using the `tls` module, you can generate TLS certificates and private keys.
|
|
4
|
+
|
|
5
|
+
The module has the following subcommands:
|
|
6
|
+
* `rootCA` - generates a CA (certification authority) self signed certificate
|
|
7
|
+
and private key pair. These are to be used by a TLS server.
|
|
8
|
+
* `userCERT` - generates a certificate signed by a given CA, a private key and
|
|
9
|
+
a CA list (chain of trust) file. These are to be used by TLS clients (users).
|
|
10
|
+
* `add` - adds a new TLS domain to the `tls_mgm` table.
|
|
11
|
+
* `update` - changes the columns of an existing TLS domain.
|
|
12
|
+
* `list` - lists the TLS domains provisioned in the `tls_mgm` table.
|
|
13
|
+
* `show` - prints the columns of a TLS domain.
|
|
14
|
+
* `delete` - removes a TLS domain from the `tls_mgm` table.
|
|
15
|
+
|
|
16
|
+
The `add`, `update`, `list`, `show` and `delete` subcommands provision the
|
|
17
|
+
`tls_mgm` module over the database, where the certificate, private key and CA
|
|
18
|
+
list are stored as BLOB values rather than as paths to files. A TLS domain is
|
|
19
|
+
identified by its name and its type (`server` or `client`), both passed as
|
|
20
|
+
arguments:
|
|
21
|
+
```
|
|
22
|
+
opensips-cli -x tls delete a.example.org server
|
|
23
|
+
```
|
|
24
|
+
The domain and its type may also be given by name, in which case they can
|
|
25
|
+
appear anywhere among the other columns:
|
|
26
|
+
```
|
|
27
|
+
opensips-cli -x tls delete domain=a.example.org type=server
|
|
28
|
+
```
|
|
29
|
+
Giving one of them both ways at once is an error. The commands addressing a
|
|
30
|
+
single domain ask for whatever is left out; `add` and `show` default the
|
|
31
|
+
type to `server`, while `update` and `delete` have no default and keep
|
|
32
|
+
asking until one is given, so that they cannot change a different domain than
|
|
33
|
+
the intended one.
|
|
34
|
+
|
|
35
|
+
`add` and `update` take the remaining `tls_mgm` columns as `column=value`
|
|
36
|
+
arguments, in any order and after the domain and the type:
|
|
37
|
+
```
|
|
38
|
+
opensips-cli -x tls add a.example.org server method=TLSv1_2 verify_cert=1
|
|
39
|
+
```
|
|
40
|
+
The settable columns are `match_ip_address`, `match_sip_domain`, `method`,
|
|
41
|
+
`verify_cert`, `require_cert`, `certificate`, `private_key`, `crl_check_all`,
|
|
42
|
+
`crl_dir`, `ca_list`, `ca_dir`, `cipher_list`, `dh_params` and `ec_curve`. A
|
|
43
|
+
column that is not given is left to its default in the database schema;
|
|
44
|
+
`update` only changes the columns it is given.
|
|
45
|
+
|
|
46
|
+
The `certificate`, `private_key`, `ca_list` and `dh_params` columns hold PEM
|
|
47
|
+
content, so their value is the path of the file holding it, and that file is
|
|
48
|
+
read and stored in the table:
|
|
49
|
+
```
|
|
50
|
+
opensips-cli -x tls add a.example.org server \
|
|
51
|
+
certificate=/etc/opensips/tls/user/user-cert.pem \
|
|
52
|
+
private_key=/etc/opensips/tls/user/user-privkey.pem
|
|
53
|
+
```
|
|
54
|
+
Every other column is stored as the value it is given, paths included: for
|
|
55
|
+
example, `ca_list` reads the file it points to, while `ca_dir` and `crl_dir`
|
|
56
|
+
keep the directory as such, which is what `tls_mgm` expects of them.
|
|
57
|
+
|
|
58
|
+
After every change, the `tls_reload` MI command is issued so that a running
|
|
59
|
+
OpenSIPS picks up the new domains. If OpenSIPS cannot be reached, a warning is
|
|
60
|
+
logged and the domains are loaded at the next restart.
|
|
61
|
+
|
|
62
|
+
## Configuration
|
|
63
|
+
|
|
64
|
+
Certificates and private keys can be customized using the following settings:
|
|
65
|
+
|
|
66
|
+
List of `opensips-cli.cfg` settings for configuring self-signed CA certificates:
|
|
67
|
+
|
|
68
|
+
* tls_ca_dir - output directory where the cert and key will be written to
|
|
69
|
+
* tls_ca_cert_file - output certificate file path, within `tls_ca_dir`
|
|
70
|
+
* tls_ca_key_file - output private key file path, within `tls_ca_dir`
|
|
71
|
+
* tls_ca_overwrite - set this to "y" in order to overwrite existing files
|
|
72
|
+
* tls_ca_common_name - the address of the website (e.g. "opensips.org")
|
|
73
|
+
* tls_ca_country - the initials of the country (e.g. "RO")
|
|
74
|
+
* tls_ca_state - the state (e.g. "Bucharest")
|
|
75
|
+
* tls_ca_locality - the city (e.g. "Bucharest")
|
|
76
|
+
* tls_ca_organisation - the name of the organisation (e.g. "OpenSIPS")
|
|
77
|
+
* tls_ca_organisational_unit - the organisational unit (e.g. "Project")
|
|
78
|
+
* tls_ca_notafter - the validity period, in seconds (e.g. 315360000)
|
|
79
|
+
* tls_ca_key_size - the size of the RSA key, in bits (e.g. 4096)
|
|
80
|
+
* tls_ca_md - the digest algorithm to use for signing (e.g. SHA256)
|
|
81
|
+
|
|
82
|
+
List of `opensips-cli.cfg` settings for configuring user certificates:
|
|
83
|
+
|
|
84
|
+
* tls_user_dir - output directory where the cert and key will be written to
|
|
85
|
+
* tls_user_cert_file - output certificate file path, within `tls_user_dir`
|
|
86
|
+
* tls_user_key_file - output private key file path, within `tls_user_dir`
|
|
87
|
+
* tls_user_calist_file - output CA list file path, within `tls_user_dir`
|
|
88
|
+
* tls_user_overwrite - set this to "y" in order to overwrite existing files
|
|
89
|
+
* tls_user_cacert - path to the input CA certificate
|
|
90
|
+
* tls_user_cakey - path to the input CA private key
|
|
91
|
+
* tls_user_common_name - the address of the website (e.g. "www.opensips.org")
|
|
92
|
+
* tls_user_country - the initials of the country (e.g. "RO")
|
|
93
|
+
* tls_user_state - the state (e.g. "Bucharest")
|
|
94
|
+
* tls_user_locality - the city (e.g. "Bucharest")
|
|
95
|
+
* tls_user_organisation - the name of the organisation (e.g. "OpenSIPS")
|
|
96
|
+
* tls_user_organisational_unit - the organisational unit (e.g. "Project")
|
|
97
|
+
* tls_user_notafter - the validity period, in seconds (e.g. 315360000)
|
|
98
|
+
* tls_user_key_size - the size of the RSA key, in bits (e.g. 4096)
|
|
99
|
+
* tls_user_md - the digest algorithm to use for signing (e.g. SHA256)
|
|
100
|
+
|
|
101
|
+
List of `opensips-cli.cfg` settings for the `tls_mgm` database subcommands:
|
|
102
|
+
|
|
103
|
+
* database_tls_url - URL of the database holding the `tls_mgm` table; falls
|
|
104
|
+
back to `database_url`
|
|
105
|
+
* database_tls_name - name of the database; falls back to `database_name`
|
|
106
|
+
|
|
107
|
+
|
|
108
|
+
## Examples
|
|
109
|
+
|
|
110
|
+
To create a self-signed certificate and a private key for rootCA, enter this snippet:
|
|
111
|
+
```
|
|
112
|
+
opensips-cli -x tls rootCA
|
|
113
|
+
```
|
|
114
|
+
Configuration file example for rootCA:
|
|
115
|
+
```
|
|
116
|
+
[default]
|
|
117
|
+
tls_ca_dir: /etc/opensips/tls/rootCA
|
|
118
|
+
tls_ca_cert_file: cacert.pem
|
|
119
|
+
tls_ca_key_file: private/cakey.pem
|
|
120
|
+
tls_ca_overwrite: yes
|
|
121
|
+
tls_ca_common_name: opensips.org
|
|
122
|
+
tls_ca_country: RO
|
|
123
|
+
tls_ca_state: Bucharest
|
|
124
|
+
tls_ca_locality: Bucharest
|
|
125
|
+
tls_ca_organisation: OpenSIPS
|
|
126
|
+
tls_ca_organisational_unit: Project
|
|
127
|
+
tls_ca_notafter: 315360000
|
|
128
|
+
tls_ca_key_size: 4096
|
|
129
|
+
tls_ca_md: SHA256
|
|
130
|
+
```
|
|
131
|
+
|
|
132
|
+
To create a user certificate signed by the above rootCA, along with a private
|
|
133
|
+
key and a CA list (chain of trust) file:
|
|
134
|
+
```
|
|
135
|
+
opensips-cli -x tls userCERT
|
|
136
|
+
```
|
|
137
|
+
Configuration file example for userCERT:
|
|
138
|
+
```
|
|
139
|
+
[default]
|
|
140
|
+
tls_user_dir: /etc/opensips/tls/user
|
|
141
|
+
tls_user_cert_file: user-cert.pem
|
|
142
|
+
tls_user_key_file: user-privkey.pem
|
|
143
|
+
tls_user_calist_file: user-calist.pem
|
|
144
|
+
tls_user_overwrite: yes
|
|
145
|
+
tls_user_cacert: /etc/opensips/tls/rootCA/cacert.pem
|
|
146
|
+
tls_user_cakey: /etc/opensips/tls/rootCA/private/cakey.pem
|
|
147
|
+
tls_user_common_name: www.opensips.org
|
|
148
|
+
tls_user_country: RO
|
|
149
|
+
tls_user_state: Bucharest
|
|
150
|
+
tls_user_locality: Bucharest
|
|
151
|
+
tls_user_organisation: OpenSIPS
|
|
152
|
+
tls_user_organisational_unit: Project
|
|
153
|
+
tls_user_notafter: 315360000
|
|
154
|
+
tls_user_key_size: 4096
|
|
155
|
+
tls_user_md: SHA256
|
|
156
|
+
```
|
|
157
|
+
|
|
158
|
+
To provision the certificate generated above as a TLS domain in the database:
|
|
159
|
+
```
|
|
160
|
+
opensips-cli -x tls add a.example.org server \
|
|
161
|
+
certificate=/etc/opensips/tls/user/user-cert.pem \
|
|
162
|
+
private_key=/etc/opensips/tls/user/user-privkey.pem \
|
|
163
|
+
ca_list=/etc/opensips/tls/user/user-calist.pem
|
|
164
|
+
```
|
|
165
|
+
Certificates issued by a public CA are provisioned the same way:
|
|
166
|
+
```
|
|
167
|
+
opensips-cli -x tls add a.example.org server \
|
|
168
|
+
certificate=/etc/letsencrypt/live/a.example.org/fullchain.pem \
|
|
169
|
+
private_key=/etc/letsencrypt/live/a.example.org/privkey.pem
|
|
170
|
+
```
|
|
171
|
+
Configuration file example for the `tls_mgm` database subcommands:
|
|
172
|
+
```
|
|
173
|
+
[default]
|
|
174
|
+
database_url: mysql://opensips:opensipsrw@localhost
|
|
175
|
+
database_name: opensips
|
|
176
|
+
```
|
|
177
|
+
|
|
178
|
+
To renew the certificate of a domain, or to change any of its other columns:
|
|
179
|
+
```
|
|
180
|
+
opensips-cli -x tls update a.example.org server \
|
|
181
|
+
certificate=/etc/letsencrypt/live/a.example.org/fullchain.pem \
|
|
182
|
+
private_key=/etc/letsencrypt/live/a.example.org/privkey.pem
|
|
183
|
+
opensips-cli -x tls update a.example.org server cipher_list=HIGH
|
|
184
|
+
```
|
|
185
|
+
|
|
186
|
+
To inspect and remove the provisioned domains:
|
|
187
|
+
```
|
|
188
|
+
opensips-cli -x tls list
|
|
189
|
+
opensips-cli -x tls show a.example.org server
|
|
190
|
+
opensips-cli -x tls delete a.example.org server
|
|
191
|
+
```
|
|
@@ -29,7 +29,6 @@ from opensipscli import comm
|
|
|
29
29
|
from opensipscli import defaults
|
|
30
30
|
from opensipscli.config import cfg
|
|
31
31
|
from opensipscli.logger import logger
|
|
32
|
-
from opensipscli.modules import *
|
|
33
32
|
|
|
34
33
|
class OpenSIPSCLI(cmd.Cmd, object):
|
|
35
34
|
"""
|
|
@@ -121,6 +120,10 @@ class OpenSIPSCLI(cmd.Cmd, object):
|
|
|
121
120
|
self.current_instance = instance
|
|
122
121
|
self.update_logger()
|
|
123
122
|
|
|
123
|
+
# import the modules only now, so that their import-time messages
|
|
124
|
+
# honor the logging level
|
|
125
|
+
importlib.import_module("opensipscli.modules")
|
|
126
|
+
|
|
124
127
|
# Update the intro and prompt
|
|
125
128
|
self.intro = cfg.get('prompt_intro')
|
|
126
129
|
self.prompt = '(%s): ' % cfg.get('prompt_name')
|
|
@@ -175,7 +178,11 @@ class OpenSIPSCLI(cmd.Cmd, object):
|
|
|
175
178
|
continue
|
|
176
179
|
logger.debug("Loaded module '{}'".format(name))
|
|
177
180
|
imod = mod()
|
|
178
|
-
|
|
181
|
+
methods = mod.__get_methods__(imod)
|
|
182
|
+
aliases = {}
|
|
183
|
+
if hasattr(imod, '__get_aliases__'):
|
|
184
|
+
aliases = imod.__get_aliases__() or {}
|
|
185
|
+
self.modules[name] = (imod, methods, aliases)
|
|
179
186
|
|
|
180
187
|
def history_write(self):
|
|
181
188
|
"""
|
|
@@ -419,7 +426,7 @@ class OpenSIPSCLI(cmd.Cmd, object):
|
|
|
419
426
|
logger.error("module '{}' expects the following commands: {}".
|
|
420
427
|
format(module, ", ".join(mod[1])))
|
|
421
428
|
return -1
|
|
422
|
-
elif cmd and not cmd in mod[
|
|
429
|
+
elif cmd and cmd not in mod[1] and cmd not in mod[2]:
|
|
423
430
|
logger.error("no command '{}' in module '{}'".
|
|
424
431
|
format(cmd, module))
|
|
425
432
|
return -1
|
|
@@ -36,17 +36,26 @@ try:
|
|
|
36
36
|
#from sqlalchemy.engine.url import make_url
|
|
37
37
|
|
|
38
38
|
sqlalchemy_available = True
|
|
39
|
+
sqlalchemy_import_error = None
|
|
39
40
|
logger.debug("SQLAlchemy version: %s", sqlalchemy.__version__)
|
|
40
41
|
# always use the vendored shim — the system sqlalchemy-utils package
|
|
41
42
|
# varies a lot across distros (0.36.x ships broken database_exists for
|
|
42
43
|
# PostgreSQL on Bullseye; 0.41.x is required for SA 2.0); the shim is
|
|
43
44
|
# tested against SA 1.3–2.0 and behaves consistently
|
|
44
45
|
from opensipscli.libs import sqlalchemy_utils
|
|
46
|
+
except ImportError as e:
|
|
47
|
+
# keep the cause around so callers can report it when the database
|
|
48
|
+
# is actually needed
|
|
49
|
+
logger.info("sqlalchemy not available: %s", e)
|
|
50
|
+
sqlalchemy_available = False
|
|
51
|
+
sqlalchemy_import_error = e
|
|
52
|
+
|
|
53
|
+
try:
|
|
45
54
|
import pymysql
|
|
46
55
|
pymysql.install_as_MySQLdb()
|
|
47
56
|
except ImportError:
|
|
48
|
-
|
|
49
|
-
|
|
57
|
+
# only needed for mysql:// URLs; the other backends work without it
|
|
58
|
+
pass
|
|
50
59
|
|
|
51
60
|
SUPPORTED_BACKENDS = [
|
|
52
61
|
"mysql",
|
|
@@ -767,6 +776,8 @@ class osdb(object):
|
|
|
767
776
|
check for support of a given database dialect via SQLAlchemy
|
|
768
777
|
"""
|
|
769
778
|
# TODO: do this only for SQLAlchemy
|
|
779
|
+
if not sqlalchemy_available:
|
|
780
|
+
return False
|
|
770
781
|
try:
|
|
771
782
|
sqlalchemy.create_engine('{}://'.format(dialect))
|
|
772
783
|
except sqlalchemy.exc.NoSuchModuleError:
|
|
@@ -64,6 +64,9 @@ MI_MODIFIERS = [ "-j" ]
|
|
|
64
64
|
|
|
65
65
|
class mi(Module):
|
|
66
66
|
|
|
67
|
+
def __init__(self):
|
|
68
|
+
self.aliases = {}
|
|
69
|
+
|
|
67
70
|
def print_pretty_print(self, result):
|
|
68
71
|
print(json.dumps(result, indent=4))
|
|
69
72
|
|
|
@@ -150,11 +153,34 @@ class mi(Module):
|
|
|
150
153
|
new_params.append(params[MI_ARRAY_PARAMS_COMMANDS[cmd][0]:])
|
|
151
154
|
return new_params
|
|
152
155
|
|
|
156
|
+
def __get_aliases__(self):
|
|
157
|
+
result = comm.execute('which_aliases', silent=True)
|
|
158
|
+
if not isinstance(result, list):
|
|
159
|
+
return self.aliases
|
|
160
|
+
|
|
161
|
+
aliases = {}
|
|
162
|
+
for item in result:
|
|
163
|
+
if not isinstance(item, dict):
|
|
164
|
+
continue
|
|
165
|
+
alias = item.get('alias')
|
|
166
|
+
command = item.get('command')
|
|
167
|
+
if not isinstance(alias, str) or not isinstance(command, str):
|
|
168
|
+
continue
|
|
169
|
+
if alias in aliases and aliases[alias] != command:
|
|
170
|
+
aliases[alias] = None
|
|
171
|
+
else:
|
|
172
|
+
aliases[alias] = command
|
|
173
|
+
|
|
174
|
+
self.aliases = {alias: command for alias, command in aliases.items()
|
|
175
|
+
if command is not None}
|
|
176
|
+
return self.aliases
|
|
177
|
+
|
|
153
178
|
def __invoke__(self, cmd, params=None, modifiers=None):
|
|
154
|
-
|
|
179
|
+
command = self.aliases.get(cmd, cmd)
|
|
180
|
+
params = self.parse_params(command, params, modifiers)
|
|
155
181
|
# Mi Module works with JSON Communication
|
|
156
|
-
logger.debug("running command '{}' '{}'".format(
|
|
157
|
-
res = comm.execute(
|
|
182
|
+
logger.debug("running command '{}' '{}'".format(command, params))
|
|
183
|
+
res = comm.execute(command, params)
|
|
158
184
|
if res is None:
|
|
159
185
|
return -1
|
|
160
186
|
output_type = cfg.get('output_type')
|
|
@@ -25,8 +25,38 @@ from time import gmtime, mktime
|
|
|
25
25
|
from os.path import exists, join, dirname
|
|
26
26
|
from os import makedirs
|
|
27
27
|
from opensipscli.config import cfg, OpenSIPSCLIConfig
|
|
28
|
+
from opensipscli.db import osdb, osdbError, sqlalchemy_import_error
|
|
29
|
+
from opensipscli import comm
|
|
28
30
|
from random import randrange
|
|
29
31
|
|
|
32
|
+
DEFAULT_DB_NAME = "opensips"
|
|
33
|
+
TLS_MGM_TABLE = "tls_mgm"
|
|
34
|
+
TLS_DOMAIN_COL = "domain"
|
|
35
|
+
TLS_TYPE_COL = "type"
|
|
36
|
+
TLS_CERT_COL = "certificate"
|
|
37
|
+
TLS_PK_COL = "private_key"
|
|
38
|
+
TLS_CALIST_COL = "ca_list"
|
|
39
|
+
TLS_DH_COL = "dh_params"
|
|
40
|
+
|
|
41
|
+
# the tls_mgm columns that can be provisioned
|
|
42
|
+
TLS_MGM_COLUMNS = ["match_ip_address", "match_sip_domain", "method",
|
|
43
|
+
"verify_cert", "require_cert", TLS_CERT_COL, TLS_PK_COL,
|
|
44
|
+
"crl_check_all", "crl_dir", TLS_CALIST_COL, "ca_dir", "cipher_list",
|
|
45
|
+
TLS_DH_COL, "ec_curve"]
|
|
46
|
+
|
|
47
|
+
# columns holding PEM content, which is read from the file they point to
|
|
48
|
+
TLS_PEM_COLUMNS = [TLS_CERT_COL, TLS_PK_COL, TLS_CALIST_COL, TLS_DH_COL]
|
|
49
|
+
|
|
50
|
+
# columns identifying a row, in the order they are accepted as arguments
|
|
51
|
+
TLS_KEY_COLUMNS = [TLS_DOMAIN_COL, TLS_TYPE_COL]
|
|
52
|
+
|
|
53
|
+
# generated by the database, never provisioned
|
|
54
|
+
TLS_ID_COL = "id"
|
|
55
|
+
|
|
56
|
+
# as defined by CLIENT_DOMAIN_TYPE/SERVER_DOMAIN_TYPE in tls_mgm/tls_domain.h
|
|
57
|
+
TLS_DOMAIN_TYPES = {"client": 1, "server": 2}
|
|
58
|
+
TLS_TYPE_NAMES = {v: k for k, v in TLS_DOMAIN_TYPES.items()}
|
|
59
|
+
|
|
30
60
|
openssl_version = None
|
|
31
61
|
|
|
32
62
|
try:
|
|
@@ -207,6 +237,7 @@ class tlsCryptographyKey(tlsKey):
|
|
|
207
237
|
password=None)
|
|
208
238
|
|
|
209
239
|
class tls(Module):
|
|
240
|
+
|
|
210
241
|
def do_rootCA(self, params, modifiers=None):
|
|
211
242
|
global cfg
|
|
212
243
|
logger.info("Preparing to generate CA cert + key...")
|
|
@@ -349,6 +380,312 @@ class tls(Module):
|
|
|
349
380
|
logger.info("user private key created in " + k_f)
|
|
350
381
|
logger.info("user CA list (chain of trust) created in " + ca_f)
|
|
351
382
|
|
|
383
|
+
def tls_db_connect(self):
|
|
384
|
+
"""
|
|
385
|
+
connects to the database holding the tls_mgm table
|
|
386
|
+
"""
|
|
387
|
+
if not osdb.has_sqlalchemy():
|
|
388
|
+
logger.error("SQLAlchemy not available (%s): cannot access the database",
|
|
389
|
+
sqlalchemy_import_error)
|
|
390
|
+
return None
|
|
391
|
+
|
|
392
|
+
engine = osdb.get_db_engine()
|
|
393
|
+
|
|
394
|
+
db_url = cfg.read_param(["database_tls_url", "database_url"],
|
|
395
|
+
"Please provide us the URL of the database")
|
|
396
|
+
if db_url is None:
|
|
397
|
+
print()
|
|
398
|
+
logger.error("no URL specified: aborting!")
|
|
399
|
+
return None
|
|
400
|
+
|
|
401
|
+
db_url = osdb.set_url_driver(db_url, engine)
|
|
402
|
+
db_name = cfg.read_param(["database_tls_name", "database_name"],
|
|
403
|
+
"Please provide the database storing the TLS domains",
|
|
404
|
+
DEFAULT_DB_NAME)
|
|
405
|
+
|
|
406
|
+
try:
|
|
407
|
+
db = osdb(db_url, db_name)
|
|
408
|
+
except osdbError:
|
|
409
|
+
logger.error("failed to connect to database %s", db_name)
|
|
410
|
+
return None
|
|
411
|
+
|
|
412
|
+
if not db.connect():
|
|
413
|
+
return None
|
|
414
|
+
|
|
415
|
+
return db
|
|
416
|
+
|
|
417
|
+
def tls_db_reload(self):
|
|
418
|
+
"""
|
|
419
|
+
makes a running OpenSIPS pick up the tls_mgm changes
|
|
420
|
+
"""
|
|
421
|
+
if comm.execute('tls_reload') is None:
|
|
422
|
+
logger.warning("could not reload the TLS domains; "
|
|
423
|
+
"OpenSIPS will load them at the next restart")
|
|
424
|
+
|
|
425
|
+
def tls_db_params(self, params, require_type=False):
|
|
426
|
+
"""
|
|
427
|
+
resolves the (domain, type) pair identifying a tls_mgm row, along with
|
|
428
|
+
the columns to provision. Everything is given as 'column=value', with
|
|
429
|
+
the domain and its type also accepted as the first two arguments; what
|
|
430
|
+
is left out is asked for. The value of a PEM column is the path of the
|
|
431
|
+
file holding it
|
|
432
|
+
"""
|
|
433
|
+
cols = {}
|
|
434
|
+
for param in [p for p in params if '=' in p]:
|
|
435
|
+
col, val = param.split('=', 1)
|
|
436
|
+
if col == TLS_ID_COL:
|
|
437
|
+
logger.error("column '%s' is generated by the database",
|
|
438
|
+
TLS_ID_COL)
|
|
439
|
+
return None, None, None
|
|
440
|
+
|
|
441
|
+
if col not in TLS_MGM_COLUMNS and col not in TLS_KEY_COLUMNS:
|
|
442
|
+
logger.error("unknown %s column '%s'", TLS_MGM_TABLE, col)
|
|
443
|
+
return None, None, None
|
|
444
|
+
|
|
445
|
+
if col in TLS_PEM_COLUMNS:
|
|
446
|
+
path = val
|
|
447
|
+
try:
|
|
448
|
+
with open(path, "rt") as f:
|
|
449
|
+
val = f.read()
|
|
450
|
+
except Exception as e:
|
|
451
|
+
logger.exception(e)
|
|
452
|
+
logger.error("Failed to read %s", path)
|
|
453
|
+
return None, None, None
|
|
454
|
+
|
|
455
|
+
if "-----BEGIN" not in val:
|
|
456
|
+
logger.error("%s is not in PEM format", path)
|
|
457
|
+
return None, None, None
|
|
458
|
+
|
|
459
|
+
cols[col] = val
|
|
460
|
+
|
|
461
|
+
# the domain and its type identify the row, they are not provisioned
|
|
462
|
+
args = [p for p in params if '=' not in p]
|
|
463
|
+
if len(args) > len(TLS_KEY_COLUMNS):
|
|
464
|
+
logger.error("too many arguments: expected at most a domain and "
|
|
465
|
+
"its type")
|
|
466
|
+
return None, None, None
|
|
467
|
+
|
|
468
|
+
key = {}
|
|
469
|
+
for i, col in enumerate(TLS_KEY_COLUMNS):
|
|
470
|
+
if i < len(args):
|
|
471
|
+
if col in cols:
|
|
472
|
+
logger.error("'%s' given both as an argument and as "
|
|
473
|
+
"'%s='", col, col)
|
|
474
|
+
return None, None, None
|
|
475
|
+
key[col] = args[i]
|
|
476
|
+
else:
|
|
477
|
+
key[col] = cols.pop(col, None)
|
|
478
|
+
|
|
479
|
+
domain = key[TLS_DOMAIN_COL]
|
|
480
|
+
if not domain:
|
|
481
|
+
domain = cfg.read_param(None,
|
|
482
|
+
"Please provide the name of the TLS domain")
|
|
483
|
+
if not domain:
|
|
484
|
+
logger.error("no TLS domain specified!")
|
|
485
|
+
return None, None, None
|
|
486
|
+
|
|
487
|
+
dtype = key[TLS_TYPE_COL]
|
|
488
|
+
if not dtype:
|
|
489
|
+
# commands changing an existing row get no default, so that they
|
|
490
|
+
# cannot pick a different row than the intended one
|
|
491
|
+
dtype = cfg.read_param(None, "TLS domain type (server/client)",
|
|
492
|
+
None if require_type else "server")
|
|
493
|
+
if not dtype:
|
|
494
|
+
logger.error("no TLS domain type specified!")
|
|
495
|
+
return None, None, None
|
|
496
|
+
|
|
497
|
+
if dtype.lower() not in TLS_DOMAIN_TYPES:
|
|
498
|
+
logger.error("invalid TLS domain type '%s': "
|
|
499
|
+
"expected 'server' or 'client'", dtype)
|
|
500
|
+
return None, None, None
|
|
501
|
+
|
|
502
|
+
return domain, TLS_DOMAIN_TYPES[dtype.lower()], cols
|
|
503
|
+
|
|
504
|
+
def do_add(self, params=None, modifiers=None):
|
|
505
|
+
"""
|
|
506
|
+
provisions a new TLS domain in the database
|
|
507
|
+
"""
|
|
508
|
+
domain, dtype, cols = self.tls_db_params(params or [])
|
|
509
|
+
if not domain:
|
|
510
|
+
return -1
|
|
511
|
+
|
|
512
|
+
db = self.tls_db_connect()
|
|
513
|
+
if not db:
|
|
514
|
+
return -1
|
|
515
|
+
|
|
516
|
+
row = {TLS_DOMAIN_COL: domain, TLS_TYPE_COL: dtype}
|
|
517
|
+
if db.entry_exists(TLS_MGM_TABLE, row):
|
|
518
|
+
logger.error("TLS %s domain '%s' already exists",
|
|
519
|
+
TLS_TYPE_NAMES[dtype], domain)
|
|
520
|
+
db.destroy()
|
|
521
|
+
return -1
|
|
522
|
+
|
|
523
|
+
row.update(cols)
|
|
524
|
+
if db.insert(TLS_MGM_TABLE, row) is False:
|
|
525
|
+
db.destroy()
|
|
526
|
+
return -1
|
|
527
|
+
|
|
528
|
+
db.destroy()
|
|
529
|
+
logger.info("Successfully added TLS %s domain '%s'",
|
|
530
|
+
TLS_TYPE_NAMES[dtype], domain)
|
|
531
|
+
self.tls_db_reload()
|
|
532
|
+
return True
|
|
533
|
+
|
|
534
|
+
def do_update(self, params=None, modifiers=None):
|
|
535
|
+
"""
|
|
536
|
+
changes the given columns of an existing TLS domain
|
|
537
|
+
"""
|
|
538
|
+
domain, dtype, cols = self.tls_db_params(params or [], True)
|
|
539
|
+
if not domain:
|
|
540
|
+
return -1
|
|
541
|
+
|
|
542
|
+
if not cols:
|
|
543
|
+
logger.error("no column to update: expected 'column=value'")
|
|
544
|
+
return -1
|
|
545
|
+
|
|
546
|
+
db = self.tls_db_connect()
|
|
547
|
+
if not db:
|
|
548
|
+
return -1
|
|
549
|
+
|
|
550
|
+
row = {TLS_DOMAIN_COL: domain, TLS_TYPE_COL: dtype}
|
|
551
|
+
if not db.entry_exists(TLS_MGM_TABLE, row):
|
|
552
|
+
logger.error("TLS %s domain '%s' does not exist",
|
|
553
|
+
TLS_TYPE_NAMES[dtype], domain)
|
|
554
|
+
db.destroy()
|
|
555
|
+
return -1
|
|
556
|
+
|
|
557
|
+
if db.update(TLS_MGM_TABLE, cols, row) is False:
|
|
558
|
+
db.destroy()
|
|
559
|
+
return -1
|
|
560
|
+
|
|
561
|
+
db.destroy()
|
|
562
|
+
logger.info("Successfully updated TLS %s domain '%s'",
|
|
563
|
+
TLS_TYPE_NAMES[dtype], domain)
|
|
564
|
+
self.tls_db_reload()
|
|
565
|
+
return True
|
|
566
|
+
|
|
567
|
+
def do_list(self, params=None, modifiers=None):
|
|
568
|
+
"""
|
|
569
|
+
lists the TLS domains provisioned in the database
|
|
570
|
+
"""
|
|
571
|
+
db = self.tls_db_connect()
|
|
572
|
+
if not db:
|
|
573
|
+
return -1
|
|
574
|
+
|
|
575
|
+
res = db.find(TLS_MGM_TABLE,
|
|
576
|
+
["id", TLS_DOMAIN_COL, TLS_TYPE_COL, "method",
|
|
577
|
+
"verify_cert", "require_cert"], None)
|
|
578
|
+
if res is None:
|
|
579
|
+
db.destroy()
|
|
580
|
+
return -1
|
|
581
|
+
|
|
582
|
+
rows = res.fetchall()
|
|
583
|
+
db.destroy()
|
|
584
|
+
|
|
585
|
+
if not rows:
|
|
586
|
+
logger.info("no TLS domain provisioned in %s", TLS_MGM_TABLE)
|
|
587
|
+
return True
|
|
588
|
+
|
|
589
|
+
print("{:<5} {:<32} {:<8} {:<8} {:<8} {:<8}".format(
|
|
590
|
+
"id", "domain", "type", "method", "verify", "require"))
|
|
591
|
+
for r in rows:
|
|
592
|
+
print("{:<5} {:<32} {:<8} {:<8} {:<8} {:<8}".format(
|
|
593
|
+
r[0], r[1], TLS_TYPE_NAMES.get(r[2], r[2]),
|
|
594
|
+
str(r[3]), str(r[4]), str(r[5])))
|
|
595
|
+
return True
|
|
596
|
+
|
|
597
|
+
def do_show(self, params=None, modifiers=None):
|
|
598
|
+
"""
|
|
599
|
+
prints the columns of a TLS domain
|
|
600
|
+
"""
|
|
601
|
+
domain, dtype, cols = self.tls_db_params(params or [])
|
|
602
|
+
if domain and cols:
|
|
603
|
+
logger.error("show takes no column: '%s'", list(cols)[0])
|
|
604
|
+
return -1
|
|
605
|
+
if not domain:
|
|
606
|
+
return -1
|
|
607
|
+
|
|
608
|
+
db = self.tls_db_connect()
|
|
609
|
+
if not db:
|
|
610
|
+
return -1
|
|
611
|
+
|
|
612
|
+
res = db.find(TLS_MGM_TABLE, TLS_MGM_COLUMNS,
|
|
613
|
+
{TLS_DOMAIN_COL: domain, TLS_TYPE_COL: dtype})
|
|
614
|
+
row = res.first() if res is not None else None
|
|
615
|
+
db.destroy()
|
|
616
|
+
|
|
617
|
+
if not row:
|
|
618
|
+
logger.error("TLS %s domain '%s' does not exist",
|
|
619
|
+
TLS_TYPE_NAMES[dtype], domain)
|
|
620
|
+
return -1
|
|
621
|
+
|
|
622
|
+
def decode(val):
|
|
623
|
+
return val.decode('utf-8') if isinstance(val, bytes) else val
|
|
624
|
+
|
|
625
|
+
values = dict(zip(TLS_MGM_COLUMNS, row))
|
|
626
|
+
|
|
627
|
+
print("{} domain: {}".format(TLS_TYPE_NAMES[dtype], domain))
|
|
628
|
+
for col in TLS_MGM_COLUMNS:
|
|
629
|
+
if col in TLS_PEM_COLUMNS:
|
|
630
|
+
continue
|
|
631
|
+
print("{}: {}".format(col,
|
|
632
|
+
"<empty>" if values[col] is None else values[col]))
|
|
633
|
+
|
|
634
|
+
# the private key is never printed back
|
|
635
|
+
print("{}: {}".format(TLS_PK_COL,
|
|
636
|
+
"<hidden>" if values[TLS_PK_COL] else "<empty>"))
|
|
637
|
+
|
|
638
|
+
for col in TLS_PEM_COLUMNS:
|
|
639
|
+
if col == TLS_PK_COL:
|
|
640
|
+
continue
|
|
641
|
+
print("\n{}:\n{}".format(col,
|
|
642
|
+
decode(values[col]) if values[col] else "<empty>"))
|
|
643
|
+
return True
|
|
644
|
+
|
|
645
|
+
def do_delete(self, params=None, modifiers=None):
|
|
646
|
+
"""
|
|
647
|
+
removes a TLS domain from the database
|
|
648
|
+
"""
|
|
649
|
+
domain, dtype, cols = self.tls_db_params(params or [], True)
|
|
650
|
+
if domain and cols:
|
|
651
|
+
logger.error("delete takes no column: '%s'", list(cols)[0])
|
|
652
|
+
return -1
|
|
653
|
+
if not domain:
|
|
654
|
+
return -1
|
|
655
|
+
|
|
656
|
+
db = self.tls_db_connect()
|
|
657
|
+
if not db:
|
|
658
|
+
return -1
|
|
659
|
+
|
|
660
|
+
row = {TLS_DOMAIN_COL: domain, TLS_TYPE_COL: dtype}
|
|
661
|
+
if not db.entry_exists(TLS_MGM_TABLE, row):
|
|
662
|
+
logger.error("TLS %s domain '%s' does not exist",
|
|
663
|
+
TLS_TYPE_NAMES[dtype], domain)
|
|
664
|
+
db.destroy()
|
|
665
|
+
return -1
|
|
666
|
+
|
|
667
|
+
if db.delete(TLS_MGM_TABLE, row) is False:
|
|
668
|
+
db.destroy()
|
|
669
|
+
return -1
|
|
670
|
+
|
|
671
|
+
db.destroy()
|
|
672
|
+
logger.info("Successfully deleted TLS %s domain '%s'",
|
|
673
|
+
TLS_TYPE_NAMES[dtype], domain)
|
|
674
|
+
self.tls_db_reload()
|
|
675
|
+
return True
|
|
676
|
+
|
|
677
|
+
def __complete__(self, command, text, line, begidx, endidx):
|
|
678
|
+
"""
|
|
679
|
+
helper for autocompletion in interactive mode
|
|
680
|
+
"""
|
|
681
|
+
if command not in ('add', 'update'):
|
|
682
|
+
return ['']
|
|
683
|
+
|
|
684
|
+
cols = [c + '=' for c in TLS_MGM_COLUMNS]
|
|
685
|
+
if not text:
|
|
686
|
+
return cols
|
|
687
|
+
|
|
688
|
+
return [c for c in cols if c.startswith(text)] or ['']
|
|
352
689
|
|
|
353
690
|
def __exclude__(self):
|
|
354
691
|
return (not openssl_version, None)
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Summary: Interactive command-line tool for OpenSIPS 3.0+
|
|
2
2
|
Name: opensips-cli
|
|
3
|
-
Version: 0.4.
|
|
3
|
+
Version: 0.4.2
|
|
4
4
|
Release: 0%{?dist}
|
|
5
5
|
License: GPL-3+
|
|
6
6
|
Group: System Environment/Daemons
|
|
@@ -68,6 +68,8 @@ rm -rf $RPM_BUILD_ROOT
|
|
|
68
68
|
%license LICENSE
|
|
69
69
|
|
|
70
70
|
%changelog
|
|
71
|
+
* Mon Nov 9 2026 Razvan Crainea <razvan@opensips.org> - 0.4.2-0
|
|
72
|
+
- Bump package version to 0.4.2.
|
|
71
73
|
* Thu Sep 3 2026 Stefan Darius <darius.stefan@opensips.org> - 0.4.1-0
|
|
72
74
|
- Bump package version to 0.4.1.
|
|
73
75
|
* Fri May 8 2026 Razvan Crainea <razvan@opensips.org> - 0.4.0-0
|
|
@@ -1,8 +1,20 @@
|
|
|
1
1
|
import unittest
|
|
2
|
+
from unittest.mock import patch
|
|
2
3
|
|
|
3
4
|
from opensipscli.db import make_url
|
|
5
|
+
from opensipscli.modules.mi import mi
|
|
4
6
|
|
|
5
7
|
class OpenSIPSCLIUnitTests(unittest.TestCase):
|
|
8
|
+
def testMIAliasUsesCanonicalCommand(self):
|
|
9
|
+
module = mi()
|
|
10
|
+
module.aliases = {'alias': 'canonical'}
|
|
11
|
+
|
|
12
|
+
with patch('opensipscli.modules.mi.comm.execute', return_value=None) as execute:
|
|
13
|
+
result = module.__invoke__('alias', ['key=value'], [])
|
|
14
|
+
|
|
15
|
+
self.assertEqual(result, -1)
|
|
16
|
+
execute.assert_called_once_with('canonical', {'key': 'value'})
|
|
17
|
+
|
|
6
18
|
def testMakeURL(self):
|
|
7
19
|
u = make_url('x://')
|
|
8
20
|
assert repr(u) == 'x://'
|
|
@@ -1,99 +0,0 @@
|
|
|
1
|
-
# OpenSIPS CLI - TLS module
|
|
2
|
-
|
|
3
|
-
Using the `tls` module, you can generate TLS certificates and private keys.
|
|
4
|
-
|
|
5
|
-
The module has two subcommands:
|
|
6
|
-
* `rootCA` - generates a CA (certification authority) self signed certificate
|
|
7
|
-
and private key pair. These are to be used by a TLS server.
|
|
8
|
-
* `userCERT` - generates a certificate signed by a given CA, a private key and
|
|
9
|
-
a CA list (chain of trust) file. These are to be used by TLS clients (users).
|
|
10
|
-
|
|
11
|
-
## Configuration
|
|
12
|
-
|
|
13
|
-
Certificates and private keys can be customized using the following settings:
|
|
14
|
-
|
|
15
|
-
List of `opensips-cli.cfg` settings for configuring self-signed CA certificates:
|
|
16
|
-
|
|
17
|
-
* tls_ca_dir - output directory where the cert and key will be written to
|
|
18
|
-
* tls_ca_cert_file - output certificate file path, within `tls_ca_dir`
|
|
19
|
-
* tls_ca_key_file - output private key file path, within `tls_ca_dir`
|
|
20
|
-
* tls_ca_overwrite - set this to "y" in order to overwrite existing files
|
|
21
|
-
* tls_ca_common_name - the address of the website (e.g. "opensips.org")
|
|
22
|
-
* tls_ca_country - the initials of the country (e.g. "RO")
|
|
23
|
-
* tls_ca_state - the state (e.g. "Bucharest")
|
|
24
|
-
* tls_ca_locality - the city (e.g. "Bucharest")
|
|
25
|
-
* tls_ca_organisation - the name of the organisation (e.g. "OpenSIPS")
|
|
26
|
-
* tls_ca_organisational_unit - the organisational unit (e.g. "Project")
|
|
27
|
-
* tls_ca_notafter - the validity period, in seconds (e.g. 315360000)
|
|
28
|
-
* tls_ca_key_size - the size of the RSA key, in bits (e.g. 4096)
|
|
29
|
-
* tls_ca_md - the digest algorithm to use for signing (e.g. SHA256)
|
|
30
|
-
|
|
31
|
-
List of `opensips-cli.cfg` settings for configuring user certificates:
|
|
32
|
-
|
|
33
|
-
* tls_user_dir - output directory where the cert and key will be written to
|
|
34
|
-
* tls_user_cert_file - output certificate file path, within `tls_user_dir`
|
|
35
|
-
* tls_user_key_file - output private key file path, within `tls_user_dir`
|
|
36
|
-
* tls_user_calist_file - output CA list file path, within `tls_user_dir`
|
|
37
|
-
* tls_user_overwrite - set this to "y" in order to overwrite existing files
|
|
38
|
-
* tls_user_cacert - path to the input CA certificate
|
|
39
|
-
* tls_user_cakey - path to the input CA private key
|
|
40
|
-
* tls_user_common_name - the address of the website (e.g. "www.opensips.org")
|
|
41
|
-
* tls_user_country - the initials of the country (e.g. "RO")
|
|
42
|
-
* tls_user_state - the state (e.g. "Bucharest")
|
|
43
|
-
* tls_user_locality - the city (e.g. "Bucharest")
|
|
44
|
-
* tls_user_organisation - the name of the organisation (e.g. "OpenSIPS")
|
|
45
|
-
* tls_user_organisational_unit - the organisational unit (e.g. "Project")
|
|
46
|
-
* tls_user_notafter - the validity period, in seconds (e.g. 315360000)
|
|
47
|
-
* tls_user_key_size - the size of the RSA key, in bits (e.g. 4096)
|
|
48
|
-
* tls_user_md - the digest algorithm to use for signing (e.g. SHA256)
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
## Examples
|
|
52
|
-
|
|
53
|
-
To create a self-signed certificate and a private key for rootCA, enter this snippet:
|
|
54
|
-
```
|
|
55
|
-
opensips-cli -x tls rootCA
|
|
56
|
-
```
|
|
57
|
-
Configuration file example for rootCA:
|
|
58
|
-
```
|
|
59
|
-
[default]
|
|
60
|
-
tls_ca_dir: /etc/opensips/tls/rootCA
|
|
61
|
-
tls_ca_cert_file: cacert.pem
|
|
62
|
-
tls_ca_key_file: private/cakey.pem
|
|
63
|
-
tls_ca_overwrite: yes
|
|
64
|
-
tls_ca_common_name: opensips.org
|
|
65
|
-
tls_ca_country: RO
|
|
66
|
-
tls_ca_state: Bucharest
|
|
67
|
-
tls_ca_locality: Bucharest
|
|
68
|
-
tls_ca_organisation: OpenSIPS
|
|
69
|
-
tls_ca_organisational_unit: Project
|
|
70
|
-
tls_ca_notafter: 315360000
|
|
71
|
-
tls_ca_key_size: 4096
|
|
72
|
-
tls_ca_md: SHA256
|
|
73
|
-
```
|
|
74
|
-
|
|
75
|
-
To create a user certificate signed by the above rootCA, along with a private
|
|
76
|
-
key and a CA list (chain of trust) file:
|
|
77
|
-
```
|
|
78
|
-
opensips-cli -x tls userCERT
|
|
79
|
-
```
|
|
80
|
-
Configuration file example for userCERT:
|
|
81
|
-
```
|
|
82
|
-
[default]
|
|
83
|
-
tls_user_dir: /etc/opensips/tls/user
|
|
84
|
-
tls_user_cert_file: user-cert.pem
|
|
85
|
-
tls_user_key_file: user-privkey.pem
|
|
86
|
-
tls_user_calist_file: user-calist.pem
|
|
87
|
-
tls_user_overwrite: yes
|
|
88
|
-
tls_user_cacert: /etc/opensips/tls/rootCA/cacert.pem
|
|
89
|
-
tls_user_cakey: /etc/opensips/tls/rootCA/private/cakey.pem
|
|
90
|
-
tls_user_common_name: www.opensips.org
|
|
91
|
-
tls_user_country: RO
|
|
92
|
-
tls_user_state: Bucharest
|
|
93
|
-
tls_user_locality: Bucharest
|
|
94
|
-
tls_user_organisation: OpenSIPS
|
|
95
|
-
tls_user_organisational_unit: Project
|
|
96
|
-
tls_user_notafter: 315360000
|
|
97
|
-
tls_user_key_size: 4096
|
|
98
|
-
tls_user_md: SHA256
|
|
99
|
-
```
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|