Skip to content
Snippets Groups Projects
Commit 45d80080 authored by Thomas Woerner's avatar Thomas Woerner
Browse files

ipaserver: Add support for external signed CA

This adds support for the --external-ca option to ipaserver. Lots of
additional tests and checks from ServerInstallInterface.__init__ have
been added to ipaserver_test. Also duplicate tests cna checks have been
removed.

Installer settings in ansible_ipa_server module_util are now also set
to the defaults that are used in Installable, ServerInstallInterface,
ServerMasterInstall, ADTrustInstallInterface and Uninstall.

The /root/ipa.csr file generated on the node in ca.install_step_0 will
be copied to the controller as "{{ inventory_hostname }}-ipa.csr".

The new task file copy_external_cert.yml has been added to copy the
generated certificate defined in ipaserver_external_cert_files to the node
to continue with ca.install_step_1.

The tasks/install.yml file has been adapted to make sure that the steps
that will be done in step two will be skipped after step one has been
done.
parent 5f580b51
Branches
Tags
No related merge requests found
......@@ -42,11 +42,11 @@ Requirements
Limitations
-----------
External CA
External signed CA
External CA support is not supported or working. The currently needed two step process is an issue for the processing in the role. The configuration of the server is partly done already and needs to be continued after the CSR has been handled. This is for example breaking the deployment of a server with replicas or clients in one playbook.
External signed CA is now supported. But the currently needed two step process is an issue for the processing in a simple playbook.
Work is planned to have a new method to handle CSR for external CAs in a separate step before starting the server installation.
Work is planned to have a new method to handle CSR for external signed CAs in a separate step before starting the server installation.
Usage
......@@ -106,6 +106,56 @@ Example playbook to setup the IPA server using admin and dirman passwords from i
- role: ipaserver
state: present
Example playbook to setup the IPA primary with external signed CA using the previous inventory file:
Server installation step 1: Generate CSR, copy to controller as `<ipaserver hostname>-ipa.csr`
```yaml
---
- name: Playbook to configure IPA server step1
hosts: ipaserver
become: true
vars:
ipaserver_external_ca: yes
roles:
- role: ipaserver
state: present
post_tasks:
- name: Copy CSR /root/ipa.csr from node to "{{ groups.ipaserver[0] + '-ipa.csr' }}"
fetch:
src: /root/ipa.csr
dest: "{{ groups.ipaserver[0] + '-ipa.csr' }}"
flat: yes
```
Sign with CA: This is up to you
Server installatin step 2: Copy `<ipaserver hostname>-chain.crt` to the IPA server and continue with installation of the primary.
```yaml
- name: Playbook to configure IPA server step3
hosts: ipaserver
become: true
vars:
ipaserver_external_cert_files: "/root/chain.crt"
pre_tasks:
- name: Copy "{{ groups.ipaserver[0] + '-chain.crt' }}" to /root/chain.crt on node
copy:
src: "{{ groups.ipaserver[0] + '-chain.crt' }}"
dest: "/root/chain.crt"
force: yes
roles:
- role: ipaserver
state: present
```
The files can also be copied automatically: Set `ipaserver_copy_csr_to_controller` to true in the server installation step 1 and set `ipaserver_external_cert_files_from_controller` to point to the `chain.crt` file in the server installatin step 2.
Playbooks
=========
......@@ -192,13 +242,13 @@ Certificate system Variables
Variable | Description | Required
-------- | ----------- | --------
~~`ipaserver_external_ca`~~ | ~~Generate a CSR for the IPA CA certificate to be signed by an external CA. (bool, default: false)~~ | ~~no~~
~~`ipaserver_external_ca_type`~~ | ~~Type of the external CA. (choice: generic,ms-cs)~~ | ~~no~~
~~`ipaserver_external_ca_profile`~~ | ~~Specify the certificate profile/template to use at the external CA. (string)~~ | ~~no~~
~~`ipaserver_external_cert_files`~~ | ~~Files containing the IPA CA certificates and the external CA certificate chains (list of string)~~ | ~~no~~
`ipaserver_external_ca` | Generate a CSR for the IPA CA certificate to be signed by an external CA. (bool, default: false) | no
`ipaserver_external_ca_type` | Type of the external CA. (choice: generic,ms-cs) | no
`ipaserver_external_ca_profile` | Specify the certificate profile/template to use at the external CA. (string) | no
`ipaserver_external_cert_files` | Files containing the IPA CA certificates and the external CA certificate chains (list of string) | no
`ipaserver_subject_base` | The certificate subject base (default O=<realm-name>). RDNs are in LDAP order (most specific RDN first). (string) | no
`ipaserver_ca_subject` | The CA certificate subject DN (default CN=Certificate Authority,O=<realm-name>). RDNs are in LDAP order (most specific RDN first). (string) | no
~~`ipaserver_ca_signing_algorithm`~~ | ~~Signing algorithm of the IPA CA certificate. (choice: SHA1withRSA,SHA256withRSA,SHA512withRSA)~~ | ~~no~~
`ipaserver_ca_signing_algorithm` | Signing algorithm of the IPA CA certificate. (choice: SHA1withRSA,SHA256withRSA,SHA512withRSA) | no
DNS Variables
-------------
......@@ -233,7 +283,8 @@ Variable | Description | Required
-------- | ----------- | --------
`ipaserver_install_packages` | The bool value defines if the needed packages are installed on the node. (bool, default: true) | no
`ipaserver_setup_firewalld` | The value defines if the needed services will automatically be openen in the firewall managed by firewalld. (bool, default: true) | no
`ipaserver_external_cert_files_from_controller` | Files containing the IPA CA certificates and the external CA certificate chains on the controller that will be copied to the ipaserver host to `/root` folder. (list of string) | no
`ipaserver_copy_csr_to_controller` | Copy the generated CSR from the ipaserver to the controller as `"{{ inventory_hostname }}-ipa.csr"`. (bool) | no
Authors
=======
......
......@@ -36,7 +36,7 @@ ipaserver_install_packages: yes
ipaserver_setup_firewalld: yes
### additional ###
ipaserver_allow_missing: [ ]
ipaserver_copy_csr_to_controller: no
### uninstall ###
ipaserver_ignore_topology_disconnect: no
......
......@@ -97,7 +97,9 @@ def main():
### ssl certificate ###
### client ###
### certificate system ###
external_ca=dict(required=False),
external_ca=dict(required=False, type='bool'),
external_ca_type=dict(required=False),
external_ca_profile=dict(required=False),
external_cert_files=dict(required=False, type='list', default=[]),
subject_base=dict(required=False),
ca_subject=dict(required=False),
......@@ -152,6 +154,9 @@ def main():
#options.no_ntp = ansible_module.params.get('no_ntp')
### certificate system ###
options.external_ca = ansible_module.params.get('external_ca')
options.external_ca_type = ansible_module.params.get('external_ca_type')
options.external_ca_profile = ansible_module.params.get(
'external_ca_profile')
options.external_cert_files = ansible_module.params.get(
'external_cert_files')
options.subject_base = ansible_module.params.get('subject_base')
......
......@@ -106,7 +106,9 @@ def main():
_dirsrv_pkcs12_info=dict(required=False),
### certificate system ###
external_ca=dict(required=False, type='bool', default=False),
external_cert_files=dict(required=False, type='list', default=[]),
external_ca_type=dict(required=False),
external_ca_profile=dict(required=False),
external_cert_files=dict(required=False, type='list', default=None),
subject_base=dict(required=False),
_subject_base=dict(required=False),
ca_subject=dict(required=False),
......@@ -154,6 +156,9 @@ def main():
'_dirsrv_pkcs12_info')
### certificate system ###
options.external_ca = ansible_module.params.get('external_ca')
options.external_ca_type = ansible_module.params.get('external_ca_type')
options.external_ca_profile = ansible_module.params.get(
'external_ca_profile')
options.external_cert_files = ansible_module.params.get(
'external_cert_files')
options.subject_base = ansible_module.params.get('subject_base')
......@@ -175,6 +180,13 @@ def main():
options.promote = False # first master, no promotion
# Repeat from ca.install_check
# ca.external_cert_file and ca.external_ca_file need to be set
if options.external_cert_files:
ca.external_cert_file, ca.external_ca_file = \
installutils.load_external_cert(
options.external_cert_files, options._ca_subject)
fstore = sysrestore.FileStore(paths.SYSRESTORE)
api_Backend_ldap2(options.host_name, options.setup_ca, connect=True)
......@@ -190,13 +202,14 @@ def main():
# setup CA ##############################################################
with redirect_stdout(ansible_log):
if hasattr(custodiainstance, "get_custodia_instance"):
if hasattr(custodiainstance.CustodiaModes, "FIRST_MASTER"):
mode = custodiainstance.CustodiaModes.FIRST_MASTER
else:
mode = custodiainstance.CustodiaModes.MASTER_PEER
custodia = custodiainstance.get_custodia_instance(options, mode)
custodia.set_output(ansible_log)
with redirect_stdout(ansible_log):
custodia.create_instance()
if options.setup_ca:
......@@ -206,10 +219,15 @@ def main():
if n in options.__dict__}
write_cache(cache_vars)
try:
with redirect_stdout(ansible_log):
if hasattr(custodiainstance, "get_custodia_instance"):
ca.install_step_0(False, None, options, custodia=custodia)
else:
ca.install_step_0(False, None, options)
except SystemExit:
ansible_module.exit_json(changed=True,
csr_generated=True)
else:
# Put the CA cert where other instances expect it
x509.write_certificate(options._http_ca_cert, paths.IPA_CA_CRT)
......@@ -226,6 +244,7 @@ def main():
x509.write_certificate(options._http_ca_cert, paths.CA_BUNDLE_PEM)
os.chmod(paths.CA_BUNDLE_PEM, 0o444)
with redirect_stdout(ansible_log):
# we now need to enable ssl on the ds
ds.enable_ssl()
......@@ -236,7 +255,8 @@ def main():
else:
ca.install_step_1(False, None, options)
ansible_module.exit_json(changed=True)
ansible_module.exit_json(changed=True,
csr_generated=False)
if __name__ == '__main__':
main()
This diff is collapsed.
......@@ -100,7 +100,7 @@ if NUM_VERSION >= 40500:
update_hosts_file)
from ipaserver.install.server.install import (
check_dirsrv, validate_admin_password, validate_dm_password,
write_cache)
read_cache, write_cache)
try:
from ipaserver.install.dogtaginstance import PKIIniLoader
except ImportError:
......@@ -218,6 +218,39 @@ options.add_sids = True
options.add_agents = False
# Installable
options.uninstalling = False
# ServerInstallInterface
options.description = "Server"
options.kinit_attempts = 1
options.fixed_primary = True
options.permit = False
options.enable_dns_updates = False
options.no_krb5_offline_passwords = False
options.preserve_sssd = False
options.no_sssd = False
# ServerMasterInstall
options.force_join = False
options.servers = None
options.no_wait_for_dns = True
options.host_password = None
options.keytab = None
options.setup_ca = True
# always run sidgen task and do not allow adding agents on first master
options.add_sids = True
options.add_agents = False
# ADTrustInstallInterface
# no_msdcs is deprecated
options.no_msdcs = False
# Uninstall
options.ignore_topology_disconnect = False
options.ignore_last_of_role = False
def api_Backend_ldap2(host_name, setup_ca, connect=False):
# we are sure we have the configuration file ready.
cfg = dict(context='installer', confdir=paths.ETC_IPA, in_server=True,
......
- name: Install - Initialize ipaserver_external_cert_files
set_fact:
ipaserver_external_cert_files: []
when: ipaserver_external_cert_files is undefined
- name: Install - Copy "{{ item }}" "{{ inventory_hostname }}':/root/'{{ item }}"
copy:
src: "{{ item }}"
dest: "/root/{{ item }}"
force: yes
- name: Install - Extend ipaserver_external_cert_files with "/root/{{ item }}"
set_fact:
ipaserver_external_cert_files: "{{ ipaserver_external_cert_files }} + [ '/root/{{ item }}' ]"
......@@ -24,6 +24,12 @@
#- name: Install - Include Python2/3 import test
# import_tasks: "{{ role_path }}/tasks/python_2_3_test.yml"
- include_tasks: "{{ role_path }}/tasks/copy_external_cert.yml"
with_items: "{{ ipaserver_external_cert_files_from_controller }}"
when: ipaserver_external_cert_files_from_controller is defined and
ipaserver_external_cert_files_from_controller|length > 0 and
not ipaserver_external_cert_files is defined
- name: Install - Server installation test
ipaserver_test:
### basic ###
......@@ -47,9 +53,9 @@
# no_ui_redirect: "{{ ipaserver_no_ui_redirect }}"
dirsrv_config_file: "{{ ipaserver_dirsrv_config_file | default(omit) }}"
### ssl certificate ###
dirsrv_cert_files: "{{ ipaserver_dirsrv_cert_files | default([]) }}"
http_cert_files: "{{ ipaserver_http_cert_files | default([]) }}"
pkinit_cert_files: "{{ ipaserver_pkinit_cert_files | default([]) }}"
dirsrv_cert_files: "{{ ipaserver_dirsrv_cert_files | default(omit) }}"
http_cert_files: "{{ ipaserver_http_cert_files | default(omit) }}"
pkinit_cert_files: "{{ ipaserver_pkinit_cert_files | default(omit) }}"
# dirsrv_pin
# http_pin
# pkinit_pin
......@@ -66,7 +72,8 @@
### certificate system ###
external_ca: "{{ ipaserver_external_ca }}"
external_ca_type: "{{ ipaserver_external_ca_type | default(omit) }}"
external_cert_files: "{{ ipaserver_external_cert_files | default([]) }}"
external_ca_profile: "{{ ipaserver_external_ca_profile | default(omit) }}"
external_cert_files: "{{ ipaserver_external_cert_files | default(omit) }}"
subject_base: "{{ ipaserver_subject_base | default(omit) }}"
ca_subject: "{{ ipaserver_ca_subject | default(omit) }}"
# ca_signing_algorithm
......@@ -128,8 +135,12 @@
setup_kra: "{{ ipaserver_setup_kra }}"
setup_dns: "{{ ipaserver_setup_dns }}"
### certificate system ###
# external_ca
# external_cert_files
external_ca: "{{ ipaserver_external_ca }}"
external_ca_type: "{{ ipaserver_external_ca_type | default(omit) }}"
external_ca_profile:
"{{ ipaserver_external_ca_profile | default(omit) }}"
external_cert_files:
"{{ ipaserver_external_cert_files | default(omit) }}"
subject_base: "{{ ipaserver_subject_base | default(omit) }}"
ca_subject: "{{ ipaserver_ca_subject | default(omit) }}"
### dns ###
......@@ -174,8 +185,9 @@
setup_ca: "{{ result_ipaserver_test.setup_ca }}"
# no_host_dns: "{{ result_ipaserver_test.no_host_dns }}"
dirsrv_config_file: "{{ ipaserver_dirsrv_config_file | default(omit) }}"
dirsrv_cert_files: "{{ ipaserver_dirsrv_cert_files | default([]) }}"
external_cert_files: "{{ ipaserver_external_cert_files | default([]) }}"
dirsrv_cert_files: "{{ ipaserver_dirsrv_cert_files | default(omit) }}"
external_cert_files:
"{{ ipaserver_external_cert_files | default(omit) }}"
subject_base: "{{ result_ipaserver_prepare.subject_base }}"
ca_subject: "{{ result_ipaserver_prepare.ca_subject }}"
# no_reverse: "{{ ipaserver_no_reverse }}"
......@@ -200,7 +212,8 @@
setup_dns: "{{ ipaserver_setup_dns }}"
setup_ca: "{{ result_ipaserver_test.setup_ca }}"
no_host_dns: "{{ result_ipaserver_test.no_host_dns }}"
external_cert_files: "{{ ipaserver_external_cert_files | default([]) }}"
external_cert_files:
"{{ ipaserver_external_cert_files | default(omit) }}"
subject_base: "{{ result_ipaserver_prepare.subject_base }}"
ca_subject: "{{ result_ipaserver_prepare.ca_subject }}"
no_reverse: "{{ ipaserver_no_reverse }}"
......@@ -241,7 +254,11 @@
dirsrv_cert_files: "{{ ipaserver_dirsrv_cert_files | default([]) }}"
_dirsrv_pkcs12_info: "{{ result_ipaserver_test._dirsrv_pkcs12_info }}"
external_ca: "{{ ipaserver_external_ca }}"
external_cert_files: "{{ ipaserver_external_cert_files | default([]) }}"
external_ca_type: "{{ ipaserver_external_ca_type | default(omit) }}"
external_ca_profile:
"{{ ipaserver_external_ca_profile | default(omit) }}"
external_cert_files:
"{{ ipaserver_external_cert_files | default(omit) }}"
subject_base: "{{ result_ipaserver_prepare.subject_base }}"
_subject_base: "{{ result_ipaserver_prepare._subject_base }}"
ca_subject: "{{ result_ipaserver_prepare.ca_subject }}"
......@@ -251,7 +268,17 @@
reverse_zones: "{{ result_ipaserver_prepare.reverse_zones }}"
no_reverse: "{{ ipaserver_no_reverse }}"
auto_forwarders: "{{ ipaserver_auto_forwarders }}"
register: result_ipaserver_setup_ca
- name: Copy /root/ipa.csr to "{{ inventory_hostname }}-ipa.csr"
fetch:
src: /root/ipa.csr
dest: "{{ inventory_hostname }}-ipa.csr"
flat: yes
when: result_ipaserver_setup_ca.csr_generated | bool and
ipaserver_copy_csr_to_controller | bool
- block:
- name: Install - Setup otpd
ipaserver_setup_otpd:
realm: "{{ result_ipaserver_test.realm }}"
......@@ -274,7 +301,8 @@
setup_ca: "{{ result_ipaserver_test.setup_ca }}"
no_host_dns: "{{ result_ipaserver_test.no_host_dns }}"
dirsrv_cert_files: "{{ ipaserver_dirsrv_cert_files | default([]) }}"
external_cert_files: "{{ ipaserver_external_cert_files | default([]) }}"
external_cert_files:
"{{ ipaserver_external_cert_files | default(omit) }}"
subject_base: "{{ result_ipaserver_prepare.subject_base }}"
_subject_base: "{{ result_ipaserver_prepare._subject_base }}"
ca_subject: "{{ result_ipaserver_prepare.ca_subject }}"
......@@ -396,6 +424,8 @@
{{ "--add-service=ntp" if not ipaclient_no_ntp | bool else "" }}
when: ipaserver_setup_firewalld | bool
when: not result_ipaserver_setup_ca.csr_generated | bool
when: not ansible_check_mode and not
(not result_ipaserver_test.changed and
(result_ipaserver_test.client_already_configured is defined or
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment