Import Upstream version 4.12.4
This commit is contained in:
165
doc/workshop/1-server-install.rst
Normal file
165
doc/workshop/1-server-install.rst
Normal file
@@ -0,0 +1,165 @@
|
||||
.. _1-server-install:
|
||||
|
||||
Copyright 2015-2018 Red Hat, Inc.
|
||||
|
||||
This work is licensed under the Creative Commons Attribution 4.0
|
||||
International License. To view a copy of this license, visit
|
||||
http://creativecommons.org/licenses/by/4.0/.
|
||||
|
||||
|
||||
Unit 1: Installing the FreeIPA server
|
||||
=======================================
|
||||
|
||||
In this unit you will install a FreeIPA server. All tasks in
|
||||
subsequent units require the services and data provided by the
|
||||
server.
|
||||
|
||||
First, in the directory containing the ``Vagrantfile`` (the clone of
|
||||
this repository), execute ``vagrant up`` to bring up the Vagrant
|
||||
environment. (If you are using the VirtualBox provider on a platform
|
||||
where that is not the default, e.g. Fedora, you will also need the
|
||||
``--provider virtualbox`` option).
|
||||
|
||||
::
|
||||
|
||||
$ vagrant up --provider virtualbox
|
||||
|
||||
The Vagrant environment contains three hosts:
|
||||
|
||||
- ``server.ipademo.local``
|
||||
- ``replica.ipademo.local``
|
||||
- ``client.ipademo.local``
|
||||
|
||||
From the directory containing the ``Vagrantfile``, SSH into the
|
||||
``server`` machine::
|
||||
|
||||
$ vagrant ssh server
|
||||
|
||||
|
||||
On ``server``, start the FreeIPA server installation program::
|
||||
|
||||
[server]$ sudo ipa-server-install --no-host-dns --mkhomedir
|
||||
|
||||
The ``--no-host-dns`` argument is needed because there are no reverse
|
||||
DNS records for the Vagrant environment. For production deployment,
|
||||
this important sanity check should not be skipped. The ``--mkhomedir``
|
||||
flag configures PAM to create missing home directories when users log
|
||||
into the host for the first time. FreeIPA supports automount so
|
||||
consider using that for production deployments.
|
||||
|
||||
You will be asked a series of questions. Accept the defaults for most
|
||||
of the questions, except as outlined below.
|
||||
|
||||
Configure FreeIPA's DNS server::
|
||||
|
||||
Do you want to configure integrated DNS (BIND)? [no]: yes
|
||||
|
||||
|
||||
Accept default values for the server hostname, domain name and realm::
|
||||
|
||||
Enter the fully qualified domain name of the computer
|
||||
on which you're setting up server software. Using the form
|
||||
<hostname>.<domainname>
|
||||
Example: master.example.com.
|
||||
|
||||
|
||||
Server host name [server.ipademo.local]:
|
||||
|
||||
Warning: skipping DNS resolution of host server.ipademo.local
|
||||
The domain name has been determined based on the host name.
|
||||
|
||||
Please confirm the domain name [ipademo.local]:
|
||||
|
||||
The kerberos protocol requires a Realm name to be defined.
|
||||
This is typically the domain name converted to uppercase.
|
||||
|
||||
Please provide a realm name [IPADEMO.LOCAL]:
|
||||
|
||||
|
||||
Enter passwords for *Directory Manager* (used to manage the
|
||||
directory server) and *admin* (the main account used for FreeIPA
|
||||
administration). Use something simple that you're not going to
|
||||
forget during the workshop!
|
||||
|
||||
::
|
||||
|
||||
Certain directory server operations require an administrative user.
|
||||
This user is referred to as the Directory Manager and has full access
|
||||
to the Directory for system management tasks and will be added to the
|
||||
instance of directory server created for IPA.
|
||||
The password must be at least 8 characters long.
|
||||
|
||||
Directory Manager password:
|
||||
Password (confirm):
|
||||
|
||||
The IPA server requires an administrative user, named 'admin'.
|
||||
This user is a regular system account used for IPA server administration.
|
||||
|
||||
IPA admin password:
|
||||
Password (confirm):
|
||||
|
||||
|
||||
Do not configure a DNS forwarder (you will want to configure a DNS
|
||||
forwarder for a real-world deployment but it is not needed for this
|
||||
workshop) and accept the defaults for configuring the reverse zone::
|
||||
|
||||
Checking DNS domain ipademo.local., please wait ...
|
||||
Do you want to configure DNS forwarders? [yes]: no
|
||||
No DNS forwarders configured
|
||||
Do you want to search for missing reverse zones? [yes]:
|
||||
Do you want to create reverse zone for IP 192.168.33.10 [yes]:
|
||||
Please specify the reverse zone name [33.168.192.in-addr.arpa.]:
|
||||
Using reverse zone(s) 33.168.192.in-addr.arpa.
|
||||
|
||||
Next, you will be presented with a summary of the server
|
||||
configuration and asked for final confirmation. Give confirmation to begin the
|
||||
server installation::
|
||||
|
||||
The IPA Master Server will be configured with:
|
||||
Hostname: server.ipademo.local
|
||||
IP address(es): 192.168.33.10
|
||||
Domain name: ipademo.local
|
||||
Realm name: IPADEMO.LOCAL
|
||||
|
||||
The CA will be configured with:
|
||||
Subject DN: CN=Certificate Authority,O=IPADEMO.LOCAL
|
||||
Subject base: O=IPADEMO.LOCAL
|
||||
Chaining: self-signed
|
||||
|
||||
BIND DNS server will be configured to serve IPA domain with:
|
||||
Forwarders: No forwarders
|
||||
Forward policy: only
|
||||
Reverse zone(s): 33.168.192.in-addr.arpa.
|
||||
|
||||
Continue to configure the system with these values? [no]: yes
|
||||
|
||||
The installation takes a few minutes; you will see output indicating
|
||||
the progress.
|
||||
|
||||
When it completes, run ``kinit admin`` and enter your *admin*
|
||||
password to obtain a Kerberos *ticket granting ticket* (TGT) for the
|
||||
``admin`` user::
|
||||
|
||||
[server]$ kinit admin
|
||||
Password for admin@IPADEMO.LOCAL: <enter password>
|
||||
|
||||
Run ``klist`` to view your current Kerberos tickets::
|
||||
|
||||
[server]$ klist
|
||||
Ticket cache: KEYRING:persistent:1000:1000
|
||||
Default principal: admin@IPADEMO.LOCAL
|
||||
|
||||
Valid starting Expires Service principal
|
||||
10/15/15 01:48:59 10/16/15 01:48:57 krbtgt/IPADEMO.LOCAL@IPADEMO.LOCAL
|
||||
|
||||
The FreeIPA server is now set up and you are ready to begin
|
||||
enrolling client machines, creating users, managing services, and
|
||||
more!
|
||||
|
||||
To prepare for the next unit, exit the ``server`` SSH session (but
|
||||
do not shut the VM down). The next essential unit is
|
||||
:ref:`Unit 2: Enrolling client machines <2-client-install>`.
|
||||
|
||||
Alternatively, if you would like to immediately install a replica
|
||||
server (essential for production deployments), you can take a detour
|
||||
to :ref:`Unit 7: Replica installation <7-replica-install>`.
|
||||
134
doc/workshop/10-ssh-key-management.rst
Normal file
134
doc/workshop/10-ssh-key-management.rst
Normal file
@@ -0,0 +1,134 @@
|
||||
.. _10-ssh-key-management:
|
||||
|
||||
Unit 10: SSH user and host key management
|
||||
=========================================
|
||||
|
||||
**Prerequisites:**
|
||||
|
||||
- :ref:`Unit 3: User management and Kerberos authentication <3-user-management>`
|
||||
|
||||
In this module you will explore how to use FreeIPA as a backend
|
||||
provider for SSH keys. Instead of distributing ``authorized_keys``
|
||||
and ``known_hosts`` files, SSH keys are uploaded to their
|
||||
corresponding user and host entries in FreeIPA.
|
||||
|
||||
Using FreeIPA as a backend store for SSH user keys
|
||||
--------------------------------------------------
|
||||
|
||||
OpenSSH can use *public-private key pairs* to authenticate users. A
|
||||
user wanting to access a host can get her *public key* added to an
|
||||
``authorized_keys`` file on the target host. When the user attempts
|
||||
to log in, she presents her public key and the host grants access if
|
||||
her key is in an ``authorized_keys`` file. There are system-wide
|
||||
and per-user ``authorized_keys`` files, but if the target systems do
|
||||
not mount a network-backed home directory (e.g. NFS), then the user
|
||||
must copy her public key to every system she intends to log in to.
|
||||
|
||||
On FreeIPA-enrolled systems, SSSD can be configured to cache and
|
||||
retrieve user SSH keys so that applications and services only have
|
||||
to look in one location for user public keys. FreeIPA provides the
|
||||
centralized repository of keys, which users can manage themselves.
|
||||
Administrators do not need to worry about distributing, updating or
|
||||
verifying user SSH keys.
|
||||
|
||||
Generate a user keypair on the client system::
|
||||
|
||||
[client]$ sudo -i -u alice
|
||||
[alice@client]$
|
||||
[alice@client]$ ssh-keygen -C alice@ipademo.local
|
||||
Generating public/private rsa key pair.
|
||||
Enter file in which to save the key (/home/alice/.ssh/id_rsa):
|
||||
Created directory '/home/alice/.ssh'.
|
||||
Enter passphrase (empty for no passphrase):
|
||||
Enter same passphrase again:
|
||||
Your identification has been saved in /home/alice/.ssh/id_rsa.
|
||||
Your public key has been saved in /home/alice/.ssh/id_rsa.pub.
|
||||
The key fingerprint is:
|
||||
SHA256:KZ1MQCvaGAGZxKaMxmWBexzH98NPBsTsuo1uf/42SB0 alice@ipademo.local
|
||||
The key's randomart image is:
|
||||
+---[RSA 2048]----+
|
||||
| .+=.o*oo |
|
||||
| oo+=*o* . . |
|
||||
| + ++o.=o+ . .+E|
|
||||
| o o..o.oo o o +=|
|
||||
|. .. ...S + o . .|
|
||||
| . . .. . * |
|
||||
| . + . |
|
||||
| . |
|
||||
| |
|
||||
+----[SHA256]-----+
|
||||
|
||||
The public key is stored in ``/home/alice/.ssh/id_rsa.pub`` in an
|
||||
OpenSSH-specific format. ``alice`` can now upload it to her user
|
||||
entry in FreeIPA::
|
||||
|
||||
[alice@client]$ kinit alice
|
||||
Password for alice@IPADEMO.LOCAL:
|
||||
|
||||
[alice@client]$ ipa user-mod alice \
|
||||
--sshpubkey="$(cat /home/alice/.ssh/id_rsa.pub)"
|
||||
---------------------
|
||||
Modified user "alice"
|
||||
---------------------
|
||||
User login: alice
|
||||
First name: Alice
|
||||
Last name: Able
|
||||
Home directory: /home/alice
|
||||
Login shell: /bin/sh
|
||||
Email address: alice@ipademo.local
|
||||
UID: 1278000001
|
||||
GID: 1278000001
|
||||
SSH public key: ssh-rsa
|
||||
AAAAB3NzaC1yc2EAAAADAQABAAABAQDH8pLi61DjkEPqNZnfOgGLLZfLdu9EqVL9UrZeXD3M/j3ig+xeDCCO80YjzuND0UZE4CHgA+uGrtoinQMYkt/FRkm/ie8wcinP/8BxSoOeYSHDNG+cG3iSNJrDiHoqPeQ/+nzBS5n6HWy18N5IMNoqC+f9f2VDuHWZCKqPHMLD29MAX6vOgawdHWFcAk416O+EgS43w3ub89+VPz3Egz4z9K+gjpoboFHk94n7n09B+qyzzImVMsz9vMFSr0rcaVRd9Tb0Q6HlUXkU7aH1Vjkl/DJdQalCpPYJXujkRYAZIs1ouU5IBuuq6k54fk1vBmwjv2tK2NkpvfWfhaxQVwdn
|
||||
alice@ipademo.local
|
||||
SSH public key fingerprint: C4:62:89:7A:65:F9:82:12:EF:08:96:D1:C9:7D:51:A5 alice@ipademo.local
|
||||
(ssh-rsa)
|
||||
Account disabled: False
|
||||
Password: True
|
||||
Member of groups: ipausers, sysadmin
|
||||
Indirect Member of Sudo rule: sysadmin_sudo
|
||||
Indirect Member of HBAC rule: sysadmin_all
|
||||
Kerberos keys available: True
|
||||
|
||||
During enrolment of the systems, SSSD has been configured to use
|
||||
FreeIPA as one of its identity domains and OpenSSH has been
|
||||
configured to use SSSD for managing user keys.
|
||||
|
||||
If you have disabled the ``allow_all`` HBAC rule, add a new rule
|
||||
that will **allow ``alice`` to access the ``sshd`` service on any
|
||||
host**.
|
||||
|
||||
Logging in to the server using SSH public key authentication should
|
||||
now work::
|
||||
|
||||
[alice@client]$ ssh -o GSSAPIAuthentication=no server.ipademo.local
|
||||
Enter passphrase for key '/home/alice/.ssh/id_rsa':
|
||||
Last login: Tue Feb 2 15:10:13 2016
|
||||
[alice@server]$
|
||||
|
||||
To verify that the SSH public key was used for authentication, you
|
||||
can check the ``sshd`` log on the server::
|
||||
|
||||
[server]$ sudo journalctl -u sshd -S "5 minutes ago" --no-pager
|
||||
-- Logs begin at Mon 2018-06-04 19:01:11 UTC, end at Mon 2018-06-11 04:55:19 UTC. --
|
||||
Jun 11 04:51:52 server.ipademo.local sshd[8570]: Accepted publickey for alice from 192.168.33.20 port 57596 ssh2: RSA SHA256:KZ1MQCvaGAGZxKaMxmWBexzH98NPBsTsuo1uf/42SB0
|
||||
|
||||
|
||||
Using FreeIPA as a backend store for SSH host keys
|
||||
--------------------------------------------------
|
||||
|
||||
OpenSSH uses public keys to authenticate hosts. When a client
|
||||
attempts to log in over SSH, the target host presents its public
|
||||
key. The first time the host authenticates, the user may have to
|
||||
examine the target host's public key and manually authenticate it.
|
||||
The client then stores the host's public key in a ``known_hosts``
|
||||
file. On subsequent attempts to log in, the client checks its
|
||||
``known_hosts`` files. If the presented host key does not match the
|
||||
stored host key, the OpenSSH client refuses to continue.
|
||||
|
||||
Based on the last exercise, try to figure out how to upload SSH host
|
||||
keys to the FreeIPA server.
|
||||
|
||||
**Note:** OpenSSH has already been configured to look up known hosts
|
||||
on the FreeIPA server, so no manual configuration is required for
|
||||
this section.
|
||||
453
doc/workshop/11-kerberos-ticket-policy.rst
Normal file
453
doc/workshop/11-kerberos-ticket-policy.rst
Normal file
@@ -0,0 +1,453 @@
|
||||
.. _11-kerberos-ticket-policy:
|
||||
|
||||
Unit 11: Kerberos ticket policy
|
||||
=========================================
|
||||
|
||||
**Prerequisites:**
|
||||
|
||||
- :ref:`Unit 3: User management and Kerberos authentication <3-user-management>`
|
||||
|
||||
In this module you will explore how to manage properties of Kerberos
|
||||
authentication and authorization in FreeIPA.
|
||||
|
||||
**Note:** To complete this module, FreeIPA-4.8.4 or later is needed.
|
||||
|
||||
Kerberos ticket policies
|
||||
------------------------
|
||||
|
||||
FreeIPA's primary authentication mechanism is based on Kerberos infrastructure.
|
||||
Each user has an associated Kerberos principal and potential aliases. Each FreeIPA
|
||||
service has its own Kerberos service and, optionally, alias names as well. Depending
|
||||
on who initiates a communication flow, in Kerberos terminology there are client
|
||||
and a target (server) principals. Any Kerberos principal can be used in both
|
||||
client and server roles, though typically FreeIPA services are used as targets
|
||||
and users are used as clients.
|
||||
|
||||
A client first authenticates to a Key Distribution Center (KDC) and obtains a
|
||||
ticket granting ticket (TGT). With the ticket granting ticket in possession, the
|
||||
client then asks a KDC for a service ticket to the target Kerberos principal.
|
||||
After the service ticket is issued by the KDC, the client can initiate its
|
||||
application-specific communication to the target application server.
|
||||
|
||||
When a KDC issues a ticket, there are few properties that can be controlled with
|
||||
the help of a Kerberos policy in FreeIPA. Each ticket has its own life time and
|
||||
a potential renewal age: a ticket can be renewed before its life time has ended
|
||||
but until the renewal age expired.
|
||||
|
||||
The combination of Kerberos ticket life time and renewal age altogether
|
||||
comprises a **Kerberos ticket policy**. The policy itself is not stored in a single
|
||||
place because individual parts of it are applied to different objects and at
|
||||
different stages of authentication and authorization processes. Instead, it is
|
||||
split into several parts which are associated with the corresponding Kerberos
|
||||
principals, whether they are used as clients or as targets.
|
||||
|
||||
For users, Kerberos ticket life time and renewal age can be managed with
|
||||
Kerberos ticket policy commands described in ``ipa help krbtpolicy`` manual.
|
||||
|
||||
If no specific policy is associated with a user, a default one is applied. To
|
||||
manage the default policy the same ``ipa krbtpolicy-*`` commands are used,
|
||||
without an explicit user name.
|
||||
|
||||
Display the default Kerberos ticket policy::
|
||||
|
||||
[admin@client]$ kinit admin
|
||||
Password for admin@IPADEMO.LOCAL:
|
||||
[admin@client]$ ipa krbtpolicy-show
|
||||
Max life: 86400
|
||||
Max renew: 604800
|
||||
|
||||
Modify the default policy to 8 hours max life, 1-day max renewal::
|
||||
|
||||
[admin@client]$ ipa krbtpolicy-mod --maxlife=28800 --maxrenew=86400
|
||||
Max life: 28800
|
||||
Max renew: 86640
|
||||
|
||||
Display effective Kerberos ticket policy for user ``admin``::
|
||||
|
||||
[admin@client]$ ipa krbtpolicy-show admin
|
||||
Max life: 28800
|
||||
Max renew: 86640
|
||||
|
||||
Modify per-user policy for user 'admin'::
|
||||
|
||||
[admin@client]$ ipa krbtpolicy-mod admin --maxlife=3600
|
||||
Max life: 3600
|
||||
|
||||
Reset per-user policy for user ``admin``::
|
||||
|
||||
[admin@client]$ ipa krbtpolicy-reset admin
|
||||
Max life: 28800
|
||||
Max renew: 86640
|
||||
|
||||
Currently (FreeIPA 4.8.4), FreeIPA does not allow a Kerberos service principal
|
||||
to have a custom Kerberos ticket policy. As result, only default Kerberos ticket
|
||||
policy is applicable to service principals.
|
||||
|
||||
Kerberos authentication indicators
|
||||
----------------------------------
|
||||
|
||||
A Kerberos client may have different means to prove possession of a client
|
||||
principal credentials to a KDC. There are several so-called 'pre-authentication
|
||||
mechanisms' that are used for this purpose. FreeIPA KDC is able to record which
|
||||
pre-authentication method was used when issuing the ticket granting ticket. The
|
||||
specific label is called an **authentication indicator**.
|
||||
|
||||
Authentication indicators are associated with the following pre-authentication mechanisms:
|
||||
|
||||
========================= ========================
|
||||
Authentication indicator Pre-authentication mechanism
|
||||
========================= ========================
|
||||
radius RADIUS
|
||||
otp FreeIPA two factor authentication (password + OTP)
|
||||
pkinit PKINIT, smart-card or certificate authentication
|
||||
hardened Hardened Password (by SPAKE or FAST)
|
||||
idp External Identity Provider
|
||||
========================= ========================
|
||||
|
||||
**Hardened** authentication indicator is set by FreeIPA KDC when a Kerberos
|
||||
client has used one of two pre-authentication mechanisms that allow protecting
|
||||
an exchange between the client and the KDC:
|
||||
|
||||
- **FAST** is a Kerberos pre-authentication mechanism defined in
|
||||
`RFC 6113, section 5.4 <https://tools.ietf.org/htlm/rfc6113#section-5.4>`_.
|
||||
It is used to securely pass so-called **FAST factors** to the KDC. Such
|
||||
factors might represent a traditional password-based exchange, or two-factor
|
||||
authentication, or something else. There are multiple types of FAST armors
|
||||
supported by FreeIPA.
|
||||
- **SPAKE** is a new pre-authentication mechanism,
|
||||
`being standardized <https://tools.ietf.org/html/draft-ietf-kitten-krb-spake-preauth>`_
|
||||
by the IETF Kitten working group. Its purpose is to increase security of
|
||||
Kerberos pre-authentication exchanges by making offline brute-force attacks
|
||||
infeasible and to enable use of multi-factor authentication without relying
|
||||
on FAST. SPAKE implementation in FreeIPA currently only supports a single
|
||||
factor authentication.
|
||||
|
||||
In the context of authentication indicators, FAST and SPAKE pre-authentication
|
||||
methods give higher level of protection than an exchange using encrypted
|
||||
timestamp method, traditional for Kerberos 5.
|
||||
|
||||
Each authentication indicator conveys the fact that KDC was able to
|
||||
pre-authenticate the initial ticket granting ticket exchange using chosen
|
||||
mechanism. This fact can further be used to differentiate the issued ticket life
|
||||
time and renewal age.
|
||||
|
||||
With FreeIPA 4.8.4 or later, Kerberos ticket policy allows an administrator to
|
||||
set different life time and renewal age for ticket granting tickets obtained
|
||||
with different pre-authentication methods. Each policy setting may include
|
||||
authentication indicator to say that the life time or renewal age applies to
|
||||
TGTs with which include this indicator::
|
||||
|
||||
[admin@client]$ ipa krbtpolicy-mod --help
|
||||
Usage: ipa [global-options] krbtpolicy-mod [USER] [options]
|
||||
|
||||
Modify Kerberos ticket policy.
|
||||
Options:
|
||||
-h, --help show this help message and exit
|
||||
--maxlife=INT Maximum ticket life (seconds)
|
||||
--maxrenew=INT Maximum renewable age (seconds)
|
||||
--otp-maxlife=INT OTP token maximum ticket life (seconds)
|
||||
--otp-maxrenew=INT OTP token ticket maximum renewable age (seconds)
|
||||
--radius-maxlife=INT RADIUS maximum ticket life (seconds)
|
||||
--radius-maxrenew=INT
|
||||
RADIUS ticket maximum renewable age (seconds)
|
||||
--pkinit-maxlife=INT PKINIT maximum ticket life (seconds)
|
||||
--pkinit-maxrenew=INT
|
||||
PKINIT ticket maximum renewable age (seconds)
|
||||
--hardened-maxlife=INT
|
||||
Hardened ticket maximum ticket life (seconds)
|
||||
--hardened-maxrenew=INT
|
||||
Hardened ticket maximum renewable age (seconds)
|
||||
....
|
||||
|
||||
For example, we can allow ``admin`` user to renew its ticket for two days if it
|
||||
was obtained with ``hardened`` authentication indicator::
|
||||
|
||||
[admin@client]$ ipa krbtpolicy-mod admin --hardened-maxrenew=$((2*24*60*60))
|
||||
Hardened max renew: 172800
|
||||
[admin@client]$ ipa krbtpolicy-show admin
|
||||
Max life: 28800
|
||||
Max renew: 86640
|
||||
Hardened max renew: 172800
|
||||
|
||||
There is no way to see authentication indicators for already issued tickets with
|
||||
existing Kerberos utilities. However, MIT Kerberos tracing facilities can be
|
||||
used to see what pre-authentication method was used to obtain a ticket::
|
||||
|
||||
[admin@client]$ KRB5_TRACE=/dev/stderr kinit admin
|
||||
[29708] 1583503381.62516: Getting initial credentials for admin@IPADEMO.LOCAL
|
||||
[29708] 1583503381.62518: Sending unauthenticated request
|
||||
[29708] 1583503381.62519: Sending request (176 bytes) to IPADEMO.LOCAL
|
||||
[29708] 1583503381.62520: Initiating TCP connection to stream AA.BB.CC.DD:88
|
||||
[29708] 1583503381.62521: Sending TCP request to stream AA.BB.CC.DD:88
|
||||
[29708] 1583503381.62522: Received answer (515 bytes) from stream AA.BB.CC.DD:88
|
||||
[29708] 1583503381.62523: Terminating TCP connection to stream AA.BB.CC.DD:88
|
||||
[29708] 1583503381.62524: Response was from master KDC
|
||||
[29708] 1583503381.62525: Received error from KDC: -1765328359/Additional pre-authentication required
|
||||
[29708] 1583503381.62528: Preauthenticating using KDC method data
|
||||
[29708] 1583503381.62529: Processing preauth types: PA-PK-AS-REQ (16), PA-PK-AS-REP_OLD (15), PA-PK-AS-REQ_OLD (14), PA-FX-FAST (136), PA-ETYPE-INFO2 (19), PA-PKINIT-KX (147), PA-SPAKE (151), PA-ENC-TIMESTAMP (2), PA_AS_FRESHNESS (150), PA-FX-COOKIE (133)
|
||||
[29708] 1583503381.62530: Selected etype info: etype aes256-cts, salt "SOME-VALUE", params ""
|
||||
[29708] 1583503381.62531: Received cookie: SOME-VALUE
|
||||
[29708] 1583503381.62532: PKINIT client has no configured identity; giving up
|
||||
[29708] 1583503381.62533: Preauth module pkinit (147) (info) returned: 0/Success
|
||||
[29708] 1583503381.62534: PKINIT client received freshness token from KDC
|
||||
[29708] 1583503381.62535: Preauth module pkinit (150) (info) returned: 0/Success
|
||||
[29708] 1583503381.62536: PKINIT client has no configured identity; giving up
|
||||
[29708] 1583503381.62537: Preauth module pkinit (16) (real) returned: 22/Invalid argument
|
||||
[29708] 1583503381.62538: PKINIT client ignoring draft 9 offer from RFC 4556 KDC
|
||||
[29708] 1583503381.62539: Preauth module pkinit (15) (real) returned: -1765328360/Preauthentication failed
|
||||
[29708] 1583503381.62540: PKINIT client ignoring draft 9 offer from RFC 4556 KDC
|
||||
[29708] 1583503381.62541: Preauth module pkinit (14) (real) returned: -1765328360/Preauthentication failed
|
||||
[29708] 1583503381.62542: SPAKE challenge received with group 1, pubkey 327144B7EC68505214E5A3606FD2091A7C47CBB60020D7D94B8C4878456B879E
|
||||
Password for admin@IPADEMO.LOCAL:
|
||||
[29708] 1583503386.372820: SPAKE key generated with pubkey F0AD6539C037C28758B692FA38FF8F924D5E52C593E485B3700DBF7FD2856477
|
||||
[29708] 1583503386.372821: SPAKE algorithm result: B53EC5E8C1A22F36F91FD584915F19B3F06CDF3CE460704E2C900AE83DF53EDC
|
||||
[29708] 1583503386.372822: SPAKE final transcript hash: AC42F4221481B9C9ED3169568A09BBDA9FAACE46DE13F6DCAFF8261003115A9C
|
||||
[29708] 1583503386.372823: Sending SPAKE response
|
||||
[29708] 1583503386.372824: Preauth module spake (151) (real) returned: 0/Success
|
||||
[29708] 1583503386.372825: Produced preauth for next request: PA-FX-COOKIE (133), PA-SPAKE (151)
|
||||
[29708] 1583503386.372826: Sending request (435 bytes) to IPADEMO.LOCAL
|
||||
[29708] 1583503386.372827: Initiating TCP connection to stream AA.BB.CC.DD:88
|
||||
[29708] 1583503386.372828: Sending TCP request to stream AA.BB.CC.DD:88
|
||||
[29708] 1583503386.372829: Received answer (1419 bytes) from stream AA.BB.CC.DD:88
|
||||
[29708] 1583503386.372830: Terminating TCP connection to stream AA.BB.CC.DD:88
|
||||
[29708] 1583503386.372831: Response was from master KDC
|
||||
[29708] 1583503386.372832: AS key determined by preauth: aes256-cts/AE1D
|
||||
[29708] 1583503386.372833: Decrypted AS reply; session key is: aes256-cts/12C3
|
||||
[29708] 1583503386.372834: FAST negotiation: available
|
||||
[29708] 1583503386.372835: Initializing KCM:123456 with default princ admin@IPADEMO.LOCAL
|
||||
[29708] 1583503386.372836: Storing admin@IPADEMO.LOCAL -> krbtgt/IPADEMO.LOCAL@IPADEMO.LOCAL in KCM:123456
|
||||
[29708] 1583503386.372837: Storing config in KCM:123456 for krbtgt/IPADEMO.LOCAL@IPADEMO.LOCAL: fast_avail: yes
|
||||
[29708] 1583503386.372838: Storing admin@IPADEMO.LOCAL -> krb5_ccache_conf_data/fast_avail/krbtgt\/IPADEMO.LOCAL\@IPADEMO.LOCAL@X-CACHECONF: in KCM:123456
|
||||
[29708] 1583503386.372839: Storing config in KCM:123456 for krbtgt/IPADEMO.LOCAL@IPADEMO.LOCAL: pa_type: 151
|
||||
[29708] 1583503386.372840: Storing admin@IPADEMO.LOCAL -> krb5_ccache_conf_data/pa_type/krbtgt\/IPADEMO.LOCAL\@IPADEMO.LOCAL@X-CACHECONF: in KCM:123456
|
||||
|
||||
As can be seen above, pre-authentication type, ``pa_type``, 151 (SPAKE)
|
||||
was used in for pre-authentication. A look at the credential cache content will
|
||||
show that the renewal age policy applied corresponds to the ``hardened`` variant::
|
||||
|
||||
[admin@client]$ klist -f -d -e
|
||||
Ticket cache: KCM:123456
|
||||
Default principal: admin@IPADEMO.LOCAL
|
||||
|
||||
Valid starting Expires Service principal
|
||||
06.03.2020 09.03.06 06.03.2020 17.03.06 krbtgt/IPADEMO.LOCAL@IPADEMO.LOCAL
|
||||
renew until 07.03.2020 09.03.01, Flags: FRIA
|
||||
Etype (skey, tkt): aes256-cts-hmac-sha1-96, aes256-cts-hmac-sha1-96 , AD types:
|
||||
|
||||
As result, ``admin`` user can now use its ticket up to 8 hours and renew it
|
||||
until 48 hours since the original ticket was obtained.
|
||||
|
||||
Finally, we can reset the default Kerberos ticket policy to the installation
|
||||
default::
|
||||
|
||||
[admin@client]$ ipa krbtpolicy-reset
|
||||
Max life: 86400
|
||||
Max renew: 604800
|
||||
|
||||
|
||||
Enforcing authentication indicators
|
||||
-----------------------------------
|
||||
|
||||
Authentication indicators from the ticket granting ticket are copied by the KDC
|
||||
into service tickets issued with the help of the TGT presented by a Kerberos
|
||||
client. The indicators can be seen by the applications receiving a communication
|
||||
encrypted with the service ticket. This allows an application administrator to
|
||||
permit restricted access to only those clients who used specific
|
||||
pre-authentication mechanisms to obtain their initial ticket granting ticket.
|
||||
For example, an application might decide to only allow access to a specialized
|
||||
resource to people who used smart-card authentication initially, even if the
|
||||
application itself only supports Kerberos authentication.
|
||||
|
||||
At the moment, there is only one known application that implements
|
||||
authentication indicator-based authorization. Since version 2.6.0, SSSD provides
|
||||
a PAM module ``pam_sss_gss`` which allows to authenticate users with GSSAPI
|
||||
(Kerberos ticket) and optionally check authentication indicator that was used to
|
||||
obtain this ticket. More information can be found in the man page for
|
||||
``pam_sss_gss` and for ``sssd.conf`` where options starting with ``pam_gssapi_``
|
||||
prefix are documented. This feature was also backported to SSSD 2.4.2 and 2.5.0.
|
||||
|
||||
For example, setting the following in SSSD configuration would allow GSSAPI
|
||||
authentication to ``sudo`` and ``sudo -i`` only if the Kerberos ticket was
|
||||
obtained with the use of a smartcard or certificate-based authentcation::
|
||||
|
||||
[pam]
|
||||
pam_gssapi_services = sudo, sudo-i
|
||||
pam_gssapi_indicators_map = sudo:pkinit, sudo-i:pkinit
|
||||
|
||||
The actual enforcement requires use of ``pam_sss_gss`` module in the PAM stack.
|
||||
Fedora and RHEL distributions provide ``authselect`` tool to handle PAM and NSS
|
||||
configuration. ``authselect`` was extended to allow use of ``pam_sss_gss`` as
|
||||
SSSD feature ``with-gssapi``::
|
||||
|
||||
[root@client ~]# authselect enable-feature with-gssapi
|
||||
Make sure that SSSD service is configured and enabled. See SSSD documentation for more information.
|
||||
|
||||
- with-gssapi is selected, make sure that GSSAPI authenticaiton is enabled in SSSD
|
||||
- set pam_gssapi_services to a list of allowed services in /etc/sssd/sssd.conf
|
||||
- see additional information in pam_sss_gss(8)
|
||||
|
||||
Once this change made and SSSD configuration updated to allow PAM services to
|
||||
use GSSAPI authentication, it will be possible to use Kerberos ticket to
|
||||
authenticate over a chosen PAM service. A session below demonstrates it::
|
||||
|
||||
[root@client ~]# vim /etc/sssd/sssd.conf
|
||||
[root@client ~]# systemctl restart sssd
|
||||
[root@client ~]# id testuser
|
||||
uid=167200003(testuser) gid=167200003(testuser) groups=167200003(testuser)
|
||||
[root@client ~]# ssh testuser@`hostname`
|
||||
(testuser@client.ipa.test) password:
|
||||
Last login: Thu Mar 24 13:54:21 2022 from 192.168.122.141
|
||||
-sh-5.1$ klist
|
||||
Ticket cache: KCM:167200003:41683
|
||||
Default principal: testuser@IPA.TEST
|
||||
|
||||
Valid starting Expires Service principal
|
||||
03/25/22 13:47:55 03/26/22 13:04:47 krbtgt/IPA.TEST@IPA.TEST
|
||||
-sh-5.1$ sudo -l
|
||||
Matching Defaults entries for testuser on client:
|
||||
!visiblepw, always_set_home, match_group_by_gid,
|
||||
always_query_group_plugin, env_reset, env_keep="COLORS DISPLAY HOSTNAME
|
||||
HISTSIZE KDEDIR LS_COLORS", env_keep+="MAIL QTDIR USERNAME LANG LC_ADDRESS
|
||||
LC_CTYPE", env_keep+="LC_COLLATE LC_IDENTIFICATION LC_MEASUREMENT
|
||||
LC_MESSAGES", env_keep+="LC_MONETARY LC_NAME LC_NUMERIC LC_PAPER
|
||||
LC_TELEPHONE", env_keep+="LC_TIME LC_ALL LANGUAGE LINGUAS _XKB_CHARSET
|
||||
XAUTHORITY",
|
||||
secure_path=/usr/local/sbin\:/usr/local/bin\:/usr/sbin\:/usr/bin\:/sbin\:/bin\:/var/lib/snapd/snap/bin
|
||||
|
||||
User testuser may run the following commands on dc:
|
||||
(ALL) ALL
|
||||
|
||||
FreeIPA also provides a check for an authentication indicator at KDC side. This
|
||||
means that a lack of a specific authentication indicator in TGT can result in
|
||||
denying an issuance of a requested service ticket. A consequence is that an
|
||||
application will never see any user with a ticket that does not contain a
|
||||
specified authentication indicator.
|
||||
|
||||
In order to enable the check, add authentication indicator to a service using
|
||||
``ipa service-mod`` command. We can create a new service and associate
|
||||
the ``pkinit`` authentication indicator with it::
|
||||
|
||||
[admin@client]$ ipa service-add my-service/`hostname`
|
||||
---------------------------------------------------
|
||||
Added service "my-service/client.ipademo.local@IPADEMO.LOCAL"
|
||||
---------------------------------------------------
|
||||
Principal name: my-service/client.ipademo.local@IPADEMO.LOCAL
|
||||
Principal alias: my-service/client.ipademo.local@IPADEMO.LOCAL
|
||||
Managed by: client.ipademo.local
|
||||
[admin@client]$ ipa-getkeytab -k my-service.keytab -p my-service/`hostname`
|
||||
Keytab successfully retrieved and stored in: my-service.keytab
|
||||
|
||||
A new service, ``my-service/client.ipademo.local``, was created and a set of
|
||||
random Kerberos keys was associated with it by retrieving a keytab with the
|
||||
keys. If we want to request a service ticket to the service, the service must
|
||||
have Kerberos keys.
|
||||
|
||||
MIT Kerberos provides a nice tool to request Kerberos service tickets: ``kvno``.
|
||||
At this point our service has no authentication indicator associated and a
|
||||
request will succeed::
|
||||
|
||||
[admin@client]$ KRB5_TRACE=/dev/stderr kvno -S my-service `hostname`
|
||||
[29770] 1583505522.60592: Getting credentials admin@IPADEMO.LOCAL -> my-service/client.ipademo.local@IPADEMO.LOCAL using ccache KCM:123456
|
||||
[29770] 1583505522.60593: Retrieving admin@IPADEMO.LOCAL -> my-service/client.ipademo.local@IPADEMO.LOCAL from KCM:!23456 with result: -1765328243/Matching credential not found
|
||||
[29770] 1583505522.60594: Retrieving admin@IPADEMO.LOCAL -> krbtgt/IPADEMO.LOCAL@IPADEMO.LOCAL from KCM:!23456 with result: 0/Success
|
||||
[29770] 1583505522.60595: Starting with TGT for client realm: admin@IPADEMO.LOCAL -> krbtgt/IPADEMO.LOCAL@IPADEMO.LOCAL
|
||||
[29770] 1583505522.60596: Requesting tickets for my-service/client.ipademo.local@IPADEMO.LOCAL, referrals on
|
||||
[29770] 1583505522.60597: Generated subkey for TGS request: aes256-cts/8F4D
|
||||
[29770] 1583505522.60598: etypes requested in TGS request: aes256-cts, aes128-cts, aes256-sha2, aes128-sha2, des3-cbc-sha1, rc4-hmac, camellia128-cts, camellia256-cts
|
||||
[29770] 1583505522.60600: Encoding request body and padata into FAST request
|
||||
[29770] 1583505522.60601: Sending request (1655 bytes) to IPADEMO.LOCAL
|
||||
[29770] 1583505522.60602: Initiating TCP connection to stream AA.BB.CC.DD:88
|
||||
[29770] 1583505522.60603: Sending TCP request to stream AA.BB.CC.DD:88
|
||||
[29770] 1583505522.60604: Received answer (1626 bytes) from stream AA.BB.CC.DD:88
|
||||
[29770] 1583505522.60605: Terminating TCP connection to stream AA.BB.CC.DD:88
|
||||
[29770] 1583505522.60606: Response was from master KDC
|
||||
[29770] 1583505522.60607: Decoding FAST response
|
||||
[29770] 1583505522.60608: FAST reply key: aes256-cts/71CF
|
||||
[29770] 1583505522.60609: TGS reply is for admin@IPADEMO.LOCAL -> my-service/client.ipademo.local@IPADEMO.LOCAL with session key aes256-cts/8B3E
|
||||
[29770] 1583505522.60610: TGS request result: 0/Success
|
||||
[29770] 1583505522.60611: Received creds for desired service my-service/client.ipademo.local@IPADEMO.LOCAL
|
||||
[29770] 1583505522.60612: Storing admin@IPADEMO.LOCAL -> my-service/client.ipademo.local@IPADEMO.LOCAL in KCM:123456
|
||||
my-service/client.ipademo.local@IPADEMO.LOCAL: kvno = 1
|
||||
|
||||
Let's associate ``pkinit`` authentication indicator with the service::
|
||||
|
||||
[admin@client]$ ipa service-mod my-service/`hostname` --auth-ind pkinit
|
||||
------------------------------------------------------
|
||||
Modified service "my-service/client.ipademo.local@IPADEMO.LOCAL"
|
||||
------------------------------------------------------
|
||||
Principal name: my-service/client.ipademo.local@IPADEMO.LOCAL
|
||||
Principal alias: my-service/client.ipademo.local@IPADEMO.LOCAL
|
||||
Authentication Indicators: pkinit
|
||||
Managed by: client.ipademo.local
|
||||
|
||||
Since our credentials cache already contains Kerberos ticket to
|
||||
``my-service/client.ipademo.local`` from the previous step, ``kvno`` will not
|
||||
attempt to obtain a new ticket if we just request it again. Instead, we need to
|
||||
destroy our credentials cache or specify a different one and re-try again::
|
||||
|
||||
[admin@client]$ kdestroy
|
||||
[admin@client]$ kinit admin
|
||||
Password for admin@IPADEMO.LOCAL:
|
||||
[admin@client]$ KRB5_TRACE=/dev/stderr kvno -S my-service `hostname`
|
||||
[29811] 1583506366.899807: Getting credentials admin@IPADEMO.LOCAL -> my-service/client.ipademo.local@IPADEMO.LOCAL using ccache KCM:123456
|
||||
[29811] 1583506366.899808: Retrieving admin@IPADEMO.LOCAL -> my-service/client.ipademo.local@IPADEMO.LOCAL from KCM:123456 with result: -1765328243/Matching credential not found
|
||||
[29811] 1583506366.899809: Retrieving admin@IPADEMO.LOCAL -> krbtgt/IPADEMO.LOCAL@IPADEMO.LOCAL from KCM:123456 with result: 0/Success
|
||||
[29811] 1583506366.899810: Starting with TGT for client realm: admin@IPADEMO.LOCAL -> krbtgt/IPADEMO.LOCAL@IPADEMO.LOCAL
|
||||
[29811] 1583506366.899811: Requesting tickets for my-service/client.ipademo.local@IPADEMO.LOCAL, referrals on
|
||||
[29811] 1583506366.899812: Generated subkey for TGS request: aes256-cts/8737
|
||||
[29811] 1583506366.899813: etypes requested in TGS request: aes256-cts, aes128-cts, aes256-sha2, aes128-sha2, des3-cbc-sha1, rc4-hmac, camellia128-cts, camellia256-cts
|
||||
[29811] 1583506366.899815: Encoding request body and padata into FAST request
|
||||
[29811] 1583506366.899816: Sending request (1655 bytes) to IPADEMO.LOCAL
|
||||
[29811] 1583506366.899817: Initiating TCP connection to stream AA.BB.CC.DD:88
|
||||
[29811] 1583506366.899818: Sending TCP request to stream AA.BB.CC.DD:88
|
||||
[29811] 1583506366.899819: Received answer (447 bytes) from stream AA.BB.CC.DD:88
|
||||
[29811] 1583506366.899820: Terminating TCP connection to stream AA.BB.CC.DD:88
|
||||
[29811] 1583506366.899821: Response was from master KDC
|
||||
[29811] 1583506366.899822: Decoding FAST response
|
||||
[29811] 1583506366.899823: TGS request result: -1765328372/KDC policy rejects request
|
||||
[29811] 1583506366.899824: Requesting tickets for my-service/client.ipademo.local@IPADEMO.LOCAL, referrals off
|
||||
[29811] 1583506366.899825: Generated subkey for TGS request: aes256-cts/CC99
|
||||
[29811] 1583506366.899826: etypes requested in TGS request: aes256-cts, aes128-cts, aes256-sha2, aes128-sha2, des3-cbc-sha1, rc4-hmac, camellia128-cts, camellia256-cts
|
||||
[29811] 1583506366.899828: Encoding request body and padata into FAST request
|
||||
[29811] 1583506366.899829: Sending request (1655 bytes) to IPADEMO.LOCAL
|
||||
[29811] 1583506366.899830: Initiating TCP connection to stream AA.BB.CC.DD:88
|
||||
[29811] 1583506366.899831: Sending TCP request to stream AA.BB.CC.DD:88
|
||||
[29811] 1583506366.899832: Received answer (447 bytes) from stream AA.BB.CC.DD:88
|
||||
[29811] 1583506366.899833: Terminating TCP connection to stream AA.BB.CC.DD:88
|
||||
[29811] 1583506366.899834: Response was from master KDC
|
||||
[29811] 1583506366.899835: Decoding FAST response
|
||||
[29811] 1583506366.899836: TGS request result: -1765328372/KDC policy rejects request
|
||||
kvno: KDC policy rejects request while getting credentials for my-service/client.ipademo.local@IPADEMO.LOCAL
|
||||
|
||||
Finally, we can remove the indicator from ``my-service/client.ipademo.local``::
|
||||
|
||||
[admin@client]$ ipa service-mod my-service/`hostname` --auth-ind ''
|
||||
------------------------------------------------------
|
||||
Modified service "my-service/client.ipademo.local@IPADEMO.LOCAL"
|
||||
------------------------------------------------------
|
||||
Principal name: my-service/client.ipademo.local@IPADEMO.LOCAL
|
||||
Principal alias: my-service/client.ipademo.local@IPADEMO.LOCAL
|
||||
Managed by: client.ipademo.local
|
||||
|
||||
Authentication indicators and FreeIPA services
|
||||
----------------------------------------------
|
||||
|
||||
Authentication indicators can become an effective way to enforce the use of a
|
||||
particular pre-authentication method. However, there are caveats. Since
|
||||
KDC-based enforcement does not allow anyone to obtain a service ticket to a
|
||||
Kerberos service if they do not possess an authentication indicator in question,
|
||||
great care has to be used when assigning authentication indicators to internal
|
||||
FreeIPA services.
|
||||
|
||||
Internal FreeIPA services include following Kerberos services on each IPA master
|
||||
or replica:
|
||||
|
||||
- ``HTTP/master.ipademo.local@IPADEMO.LOCAL``
|
||||
- ``ldap/master.ipademo.local@IPADEMO.LOCAL``
|
||||
- ``DNS/master.ipademo.local@IPADEMO.LOCAL``
|
||||
- ``cifs/master.ipademo.local@IPADEMO.LOCAL``
|
||||
|
||||
These services are used by automated tools and internally by FreeIPA server
|
||||
applications themselves. The tools and servers currently cannot perform
|
||||
interactive authentication steps required by PKINIT and multi-factor
|
||||
authentication methods.
|
||||
779
doc/workshop/12-external-idp-support.rst
Normal file
779
doc/workshop/12-external-idp-support.rst
Normal file
@@ -0,0 +1,779 @@
|
||||
.. _12-external-idp-support:
|
||||
|
||||
Unit 12: Authentication against external Identity Providers
|
||||
===========================================================
|
||||
|
||||
**Prerequisites:**
|
||||
|
||||
- :ref:`Unit 11: Kerberos ticket policy <11-kerberos-ticket-policy>`
|
||||
|
||||
In this module you will explore how to manage use external OAuth 2.0 servers to
|
||||
authorize issuance of Kerberos tickets in FreeIPA.
|
||||
|
||||
**Note:** To complete this module, FreeIPA-4.10 or later is needed.
|
||||
|
||||
Authentication using external Identity Providers
|
||||
------------------------------------------------
|
||||
|
||||
It is possible to let FreeIPA to delegate authentication and authorization
|
||||
process of issuing Kerberos tickets to an external entity. FreeIPA has been
|
||||
supporting RADIUS server proxying for some time. This is exposed over
|
||||
Kerberos with the help of 'otp' pre-authentication mechanism.
|
||||
|
||||
Configuration of the RADIUS proxy authentication is done in two steps: first,
|
||||
create a RADIUS proxy object in FreeIPA and then associate the user account with
|
||||
this RADIUS proxy object.
|
||||
|
||||
There is no specific requirement as to how RADIUS proxy actually authenticates
|
||||
the user. It is left outside the FreeIPA scope. The connection to the RADIUS
|
||||
server becomes critical and is important to protect.
|
||||
|
||||
This approach has been extended to allow FreeIPA to contact an OAuth 2.0
|
||||
Authorization Server instead of RADIUS server. OAuth 2.0 authorization framework
|
||||
is a modern way to delegate authorization decisions between loosely coupled
|
||||
parties. It heavily relies on the ability to use HTTP redirects to guide a
|
||||
user's browser to hop between OAuth 2.0 parties and reach the one that logs user
|
||||
in and the one that authorizes the access.
|
||||
|
||||
Traditionally, it was hard to integrate with OAuth 2.0-enabled systems in POSIX
|
||||
environment because there is no way to run a browser session from within the
|
||||
shell or console. Most of OAuth 2.0 identity providers (IdP) heavily rely on
|
||||
JavaScript and other modern browser features to provide an enhanced user
|
||||
experience. Emulating the login pages as part of line- and packet-oriented SSH
|
||||
protocol or console login script is not possible.
|
||||
|
||||
OAuth 2.0 Device Authorization Grant is defined in
|
||||
`RFC 8628 <https://www.rfc-editor.org/rfc/rfc8628>`_ and allows devices that either
|
||||
lack a browser or input constrained to obtain user authorization to access
|
||||
protected resources. Instead of performing the authorization flow right at the
|
||||
device where OAuth authorization grant is requested, a user would perform it at
|
||||
a separate device that has required rich browsing or input capabilities.
|
||||
|
||||
Following figure demonstrates a generic device authorization flow:
|
||||
|
||||
.. uml::
|
||||
|
||||
participant "End User at Browser"
|
||||
participant "Device Client"
|
||||
participant "Authorization Server"
|
||||
"Device Client" -> "Authorization Server": (A) Client Identifier
|
||||
"Authorization Server" -> "Device Client": (B) Device Code, User Code & Verification URI
|
||||
"Device Client" -> "End User at Browser": (C) User Code & Verification URI
|
||||
"End User at Browser" <-> "Authorization Server": (D) End user reviews authorization request
|
||||
"Device Client" -> "Authorization Server": (E) Polling with Device Code and Client Identifier
|
||||
"Authorization Server" -> "Device Client": (F) Access Token (& Optional Refresh Token)
|
||||
|
||||
FreeIPA implements a variation of this flow and hides it behind Kerberos KDC. A
|
||||
special pre-authentication method in MIT Kerberos, ``idp`` is implemented in
|
||||
SSSD 2.7.0 to facilitate the process outlined above.
|
||||
|
||||
Device authorization grant flow decouples the process into several steps:
|
||||
|
||||
- the device initiates OAuth 2.0 flow and receives a response from the
|
||||
Authorization Server that contains a special code and a link to a website user
|
||||
needs to visit to authorize the device;
|
||||
- user opens this website somewhere else (mobile, desktop, etc) where a proper
|
||||
browser is available;
|
||||
- user is asked to enter the special code;
|
||||
- if needed, user would be asked login into an OAuth 2.0-based IdP;
|
||||
- once logged in, IdP would ask user if they authorize this device to access
|
||||
certain user information;
|
||||
- once the access request is granted, user comes back to the device's prompt and
|
||||
confirms it;
|
||||
- the device at this point would poll OAuth 2.0 Authorization Server on whether
|
||||
it is allowed to access user information already.
|
||||
|
||||
Set up external IdP integration in FreeIPA
|
||||
------------------------------------------
|
||||
|
||||
In order to perform OAuth 2.0 device authorization grant flow against an IdP, an
|
||||
OAuth 2.0 client has to be registered with the IdP and a capability to allow the
|
||||
device authorization grant has to be given to it. Not all IdPs support this
|
||||
feature. Out of the known public ones, following IdPs do support device
|
||||
authorization grant flow:
|
||||
|
||||
* Microsoft Identity Platform, including Azure AD
|
||||
* Google
|
||||
* Github
|
||||
* Keycloak, including Red Hat SSO
|
||||
* Okta
|
||||
|
||||
Many OAuth 2.0 platforms do not support device authorization grant flow and
|
||||
cannot be directly enabled to operate with FreeIPA. However, one can always
|
||||
chain (federate) IdPs. It means that, for example, one can deploy Keycloak
|
||||
locally to allow users to sign in with identities from a different IdP. In that
|
||||
case the local Keycloak instance would need to be registered as an OAuth 2.0
|
||||
client with the remote IdP. Local Keycloak instance would then be registered
|
||||
with IPA.
|
||||
|
||||
Setting up IdP references (OAuth 2.0 clients) in IPA can be done with ``ipa
|
||||
idp-add`` command. The command accepts an option to specify a pre-defined
|
||||
template for one of the known IdPs. If none of the pre-defined templates is
|
||||
suitable, individual parameters can also be added::
|
||||
|
||||
ipa help idp-add
|
||||
Usage: ipa [global-options] idp-add NAME [options]
|
||||
|
||||
Add a new Identity Provider reference.
|
||||
Options:
|
||||
-h, --help show this help message and exit
|
||||
--auth-uri=STR OAuth 2.0 authorization endpoint
|
||||
--dev-auth-uri=STR Device authorization endpoint
|
||||
--token-uri=STR Token endpoint
|
||||
--userinfo-uri=STR User information endpoint
|
||||
--keys-uri=STR JWKS endpoint
|
||||
--issuer-url=STR The Identity Provider OIDC URL
|
||||
--client-id=STR OAuth 2.0 client identifier
|
||||
--secret OAuth 2.0 client secret
|
||||
--scope=STR OAuth 2.0 scope. Multiple scopes separated by space
|
||||
--idp-user-id=STR Attribute for user identity in OAuth 2.0 userinfo
|
||||
--setattr=STR Set an attribute to a name/value pair. Format is
|
||||
attr=value. For multi-valued attributes, the command
|
||||
replaces the values already present.
|
||||
--addattr=STR Add an attribute/value pair. Format is attr=value. The
|
||||
attribute must be part of the schema.
|
||||
--provider=['google', 'github', 'microsoft', 'okta', 'keycloak']
|
||||
Choose a pre-defined template to use
|
||||
--organization=STR Organization ID or Realm name for IdP provider
|
||||
templates
|
||||
--base-url=STR Base URL for IdP provider templates
|
||||
--all Retrieve and print all attributes from the server.
|
||||
Affects command output.
|
||||
--raw Print entries as stored on the server. Only affects
|
||||
output format.
|
||||
|
||||
In this part we would use Keycloak IdP to integrate with IPA. Next section shows
|
||||
how to set up Keycloak on a host enrolled into IPA domain. All shell scripts
|
||||
below assume execution under ``root`` privileges.
|
||||
|
||||
Set up Keycloak IdP on enrolled IPA client
|
||||
------------------------------------------
|
||||
|
||||
In this section, we set up `Keycloak <https://www.keycloak.org>`_ IdP on IPA
|
||||
client and use it to authenticate IPA users. User database in Keycloak would be
|
||||
different from the one in IPA, one would need to keep user accounts duplicated
|
||||
in both places but this would simplify our configuration. We also would use
|
||||
automation provided by the Keycloak to set up OAuth 2.0 clients and user
|
||||
accounts.
|
||||
|
||||
First, we would download keycloak and unpack it into ``/opt/keycloak-<VERSION>`` as ``root``::
|
||||
|
||||
[root@client ~]# dnf -y install java-11-openjdk-headless openssl
|
||||
|
||||
#### download keycloak ####
|
||||
[root@client ~]# export KEYCLOAK_VERSION=18.0.0
|
||||
[root@client ~]# wget https://github.com/keycloak/keycloak/releases/download/${KEYCLOAK_VERSION}/keycloak-${KEYCLOAK_VERSION}.tar.gz
|
||||
[root@client ~]# tar zxf keycloak-${KEYCLOAK_VERSION}.tar.gz -C /opt
|
||||
|
||||
#### add keycloak system user/group and folder ####
|
||||
[root@client ~]# groupadd keycloak
|
||||
[root@client ~]# useradd -r -g keycloak -d /opt/keycloak-${KEYCLOAK_VERSION} keycloak
|
||||
[root@client ~]# chown -R keycloak:keycloak /opt/keycloak-${KEYCLOAK_VERSION}
|
||||
[root@client ~]# chmod o+x /opt/keycloak-${KEYCLOAK_VERSION}/bin/
|
||||
|
||||
[root@client ~]# restorecon -R /opt/keycloak-${KEYCLOAK_VERSION}
|
||||
|
||||
Next step would be to prepare a TLS certificate to be used to protect HTTPS
|
||||
connections in Keycloak. Since our system is already enrolled into IPA, we can
|
||||
rely on two features:
|
||||
|
||||
* Enrolled IPA client has Kerberos host principal registered with keytab in ``/etc/krb5.keytab``
|
||||
* Enrolled IPA client host Kerberos principal can manage Kerberos services on the same host
|
||||
|
||||
This means we can create ``HTTP/client...`` Kerberos service right from the IPA
|
||||
client and use ``certmonger`` to issue TLS certificate for it. Certmonger would
|
||||
automatically renew the certificate. The following sequence of commands
|
||||
demonstrates how to achieve this, run as root::
|
||||
|
||||
########## setup TLS certificate using IPA CA ###############################
|
||||
[root@client ~]# kinit -k
|
||||
[root@client ~]# ipa service-add HTTP/$(hostname)
|
||||
[root@client ~]# ipa-getcert request -K HTTP/$(hostname) -D $(hostname) \
|
||||
-o keycloak -O keycloak \
|
||||
-m 0600 -M 0644 \
|
||||
-k /etc/pki/tls/private/keycloak.key \
|
||||
-f /etc/pki/tls/certs/keycloak.crt \
|
||||
-w
|
||||
|
||||
[root@client ~]# keytool -import \
|
||||
-keystore /etc/pki/tls/private/keycloak.store \
|
||||
-file /etc/ipa/ca.crt \
|
||||
-alias ipa_ca \
|
||||
-trustcacerts -storepass Secret123 -noprompt
|
||||
|
||||
[root@client ~]# chown keycloak:keycloak /etc/pki/tls/private/keycloak.store
|
||||
|
||||
The private key for this certificate is stored in
|
||||
``/etc/pki/tls/private/keycloak.key``, only accessible to the keycloak user.
|
||||
Public part of the certificate is stored in ``/etc/pki/tls/certs/keycloak.crt``
|
||||
and has permissions 0644.
|
||||
|
||||
We also import IPA CA's chain to a Java keystore that would be used by Keycloak,
|
||||
stored at ``/etc/pki/tls/private/keycloak.store``.
|
||||
|
||||
Finally, we need to set up ``systemd`` service to run Keycloak::
|
||||
|
||||
# Setup keycloak service and config files
|
||||
|
||||
[root@client ~]# cat > /etc/sysconfig/keycloak <<EOF
|
||||
KEYCLOAK_ADMIN=admin
|
||||
KEYCLOAK_ADMIN_PASSWORD=Secret123
|
||||
#KC_LOG_LEVEL=debug
|
||||
KC_HOSTNAME=$(hostname):8443
|
||||
KC_HTTPS_CERTIFICATE_FILE=/etc/pki/tls/certs/keycloak.crt
|
||||
KC_HTTPS_CERTIFICATE_KEY_FILE=/etc/pki/tls/private/keycloak.key
|
||||
KC_HTTPS_TRUST_STORE_FILE=/etc/pki/tls/private/keycloak.store
|
||||
KC_HTTPS_TRUST_STORE_PASSWORD=Secret123
|
||||
KC_HTTP_RELATIVE_PATH=/auth
|
||||
EOF
|
||||
|
||||
[root@client ~]# cat > /etc/systemd/system/keycloak.service <<EOF
|
||||
[Unit]
|
||||
Description=Keycloak Server
|
||||
After=network.target
|
||||
|
||||
[Service]
|
||||
Type=idle
|
||||
EnvironmentFile=/etc/sysconfig/keycloak
|
||||
|
||||
User=keycloak
|
||||
Group=keycloak
|
||||
ExecStart=/opt/keycloak-${KEYCLOAK_VERSION}/bin/kc.sh start
|
||||
TimeoutStartSec=600
|
||||
TimeoutStopSec=600
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
EOF
|
||||
|
||||
[root@client ~]# systemctl daemon-reload
|
||||
|
||||
|
||||
When ``systemd`` service is prepared, Keycloak needs to be initialized::
|
||||
|
||||
[root@client ~]# su - keycloak -c '''
|
||||
export KEYCLOAK_ADMIN=admin
|
||||
export KEYCLOAK_ADMIN_PASSWORD=Secret123
|
||||
export KC_HOSTNAME=$(hostname):8443
|
||||
export KC_HTTPS_CERTIFICATE_FILE=/etc/pki/tls/certs/keycloak.crt
|
||||
export KC_HTTPS_CERTIFICATE_KEY_FILE=/etc/pki/tls/private/keycloak.key
|
||||
export KC_HTTPS_TRUST_STORE_FILE=/etc/pki/tls/private/keycloak.store
|
||||
export KC_HTTPS_TRUST_STORE_PASSWORD=Secret123
|
||||
export KC_HTTP_RELATIVE_PATH=/auth
|
||||
/opt/keycloak-${KEYCLOAK_VERSION}/bin/kc.sh --verbose build
|
||||
'''
|
||||
|
||||
and can be started with the standard ``systemctl`` tool::
|
||||
|
||||
[root@client ~]# systemctl start keycloak
|
||||
|
||||
[root@client ~]# systemctl status --lines 3 --no-pager keycloak
|
||||
● keycloak.service - Keycloak Server
|
||||
Loaded: loaded (/etc/systemd/system/keycloak.service; disabled; vendor preset: disabled)
|
||||
Active: active (running) since Fri 2022-05-06 10:43:06 UTC; 9min ago
|
||||
Main PID: 27170 (java)
|
||||
Tasks: 37 (limit: 2318)
|
||||
Memory: 297.1M
|
||||
CPU: 25.560s
|
||||
CGroup: /system.slice/keycloak.service
|
||||
└─27170 java -Xms64m -Xmx512m -XX:MetaspaceSize=96M -XX:MaxMetaspaceSize=256m -Djava.net.preferIPv4Stack=true -D…
|
||||
|
||||
May 06 10:43:28 client.ipademo.local kc.sh[27170]: 2022-05-06 10:43:28,411 INFO [io.quarkus] (main) Keycloak 18.0.0 on …0.0:8443
|
||||
May 06 10:43:28 client.ipademo.local kc.sh[27170]: 2022-05-06 10:43:28,412 INFO [io.quarkus] (main) Profile prod activated.
|
||||
May 06 10:43:28 client.ipademo.local kc.sh[27170]: 2022-05-06 10:43:28,412 INFO [io.quarkus] (main) Installed features: [agroal…
|
||||
Hint: Some lines were ellipsized, use -l to show in full.
|
||||
|
||||
Now we can use it for setting up users and OAuth 2.0 clients. There are two
|
||||
handy scripts, ``kcadm.sh`` and ``kcreg.sh`` that allow to perform all
|
||||
operations without visiting the Keycloak Web UI.
|
||||
|
||||
With ``kcadm.sh`` we login as admin and create user ``testuser1`` and set a password::
|
||||
|
||||
[root@client ~]# /opt/keycloak-18.0.0/bin/kcadm.sh config truststore \
|
||||
--trustpass Secret123 \
|
||||
/etc/pki/tls/private/keycloak.store
|
||||
|
||||
[root@client ~]# /opt/keycloak-18.0.0/bin/kcadm.sh config credentials \
|
||||
--server https://$(hostname):8443/auth/ \
|
||||
--realm master --user admin --password Secret123
|
||||
Logging into https://client.ipademo.local:8443/auth/ as user admin of realm master
|
||||
|
||||
[root@client ~]# /opt/keycloak-18.0.0/bin/kcadm.sh create users \
|
||||
-r master \
|
||||
-s username=testuser1 -s enabled=true -s email=testuser1@ipademo.local
|
||||
Created new user with id 'd319b32a-4cea-43c5-8ef8-19b2b8418d0a'
|
||||
|
||||
[root@client ~]# /opt/keycloak-18.0.0/bin/kcadm.sh set-password \
|
||||
-r master \
|
||||
--username testuser1 --new-password Secret123
|
||||
|
||||
With ``kcreg.sh`` we can create OAuth 2.0 client using a pre-defined template
|
||||
that will include all parameters we need to allow OAuth 2.0 Device Authorization
|
||||
Grant flow::
|
||||
|
||||
[root@client ~]# /opt/keycloak-18.0.0/bin/kcreg.sh config credentials \
|
||||
--server https://$(hostname):8443/auth \
|
||||
--realm master --user admin --password Secret123
|
||||
|
||||
[root@client ~]# cat >ipa_client.json <<EOF
|
||||
{
|
||||
"enabled" : true,
|
||||
"redirectUris" : [ "https://ipa-ca.$(hostname -d)/ipa/idp/*" ],
|
||||
"webOrigins" : [ "https://ipa-ca.$(hostname -d)" ],
|
||||
"protocol" : "openid-connect",
|
||||
"publicClient" : true,
|
||||
"attributes" : {
|
||||
"oauth2.device.authorization.grant.enabled" : "true",
|
||||
"oauth2.device.polling.interval": "5"
|
||||
}
|
||||
}
|
||||
EOF
|
||||
|
||||
[root@client ~]# /opt/keycloak-18.0.0/bin/kcreg.sh create \
|
||||
-f ipa_client.json \
|
||||
-s clientId=ipa_oidc_client
|
||||
|
||||
At this point, we have a Keycloak instance with a default ``master`` realm
|
||||
(organization) and base URL ``https://$(hostname):8443/auth/``. In this realm we
|
||||
have created ``testuser1`` user with a simple password. We also created OAuth
|
||||
2.0 client ``ipa_oidc_client`` that is allowed to utilize OAuth 2.0 device
|
||||
authorization grant flow. This client has no client secret ("public OAuth 2.0
|
||||
client") associated. Confidential clients can also support device authorization
|
||||
grant flows.
|
||||
|
||||
The client details include information about the redirect URIs. These are required
|
||||
to specify for public OAuth 2.0 clients, but they aren't used for OAuth 2.0
|
||||
device authorization grant flow.
|
||||
|
||||
Two attributes specified in the OAuth 2.0 client definition for Keycloak:
|
||||
|
||||
- ``oauth2.device.authorization.grant.enabled``, set to ``true``, allows OAuth 2.0
|
||||
device authorization grant processing,
|
||||
- ``oauth2.device.polling.interval``, set to 5, defines the polling interval for
|
||||
the client to 5 seconds.
|
||||
|
||||
Keycloak 17.0.0 and 18.0.0 releases have a bug that sets default polling
|
||||
interval to 600 seconds. This makes impossible actual polling process as the
|
||||
lifespan of the device code is also set to 600 seconds. Keycloak's
|
||||
[pull request 11893](https://github.com/keycloak/keycloak/pull/11893) needs
|
||||
to be merged to fix the default settings.
|
||||
|
||||
Add IdP reference to IPA
|
||||
------------------------
|
||||
|
||||
The following command adds IdP reference named ``keycloak`` as IPA administrator::
|
||||
|
||||
[root@client ~]# kinit admin
|
||||
..
|
||||
[root@client ~]# echo -e "Secret123\nSecret123" | \
|
||||
[root@client ~]# ipa idp-add keycloak --provider keycloak \
|
||||
--org master \
|
||||
--base-url https://client.ipademo.local:8443/auth \
|
||||
--client-id ipa_oidc_client \
|
||||
--secret
|
||||
-----------------------------------------
|
||||
Added Identity Provider reference "keycloak"
|
||||
-----------------------------------------
|
||||
Identity Provider reference name: keycloak
|
||||
Authorization URI: https://client.ipademo.local:8443/auth/realms/master/protocol/openid-connect/auth
|
||||
Device authorization URI: https://client.ipademo.local:8443/auth/realms/master/protocol/openid-connect/auth/device
|
||||
Token URI: https://client.ipademo.local:8443/auth/realms/master/protocol/openid-connect/token
|
||||
User info URI: https://client.ipademo.local:8443/auth/realms/master/protocol/openid-connect/userinfo
|
||||
Client identifier: ipa_oidc_client
|
||||
Secret: U2VjcmV0MTIz
|
||||
Scope: openid email
|
||||
External IdP user identifier attribute: email
|
||||
|
||||
The name for the IdP reference is only used to associate an IdP with users in
|
||||
IPA. Option ``--provider keycloak`` allows us to fill-in pre-defined template
|
||||
for Keycloak or Red Hat SSO IdPs. The template expects both Keycloak's realm
|
||||
(``--org`` option) and a base URL (``--base-url`` option) because Keycloak is
|
||||
typically deployed as a part of a larger solution. These options may not be
|
||||
needed for other pre-defined templates like Google or Github.
|
||||
|
||||
The `openid` scope is mandatory since
|
||||
[Keycloak 19.0.2](https://www.keycloak.org/docs/latest/upgrading/index.html#userinfo-endpoint-changes).
|
||||
Without the `openid` scope, Keycloak refuses userinfo requests with HTTP
|
||||
response 403: `invalid_scope` `Missing openid scope`.
|
||||
|
||||
Associate IdP reference with IPA user
|
||||
-------------------------------------
|
||||
|
||||
While we have added ``testuser1`` to Keycloak instance, this user needs to exist
|
||||
in IPA to be visible to all enrolled systems. Currently there is no good
|
||||
solution to integrate between IPA and Keycloak to allow automatically propagate
|
||||
changes between the two. For the purpose of this workshop we would create users
|
||||
manually -- we already did that for Keycloak.
|
||||
|
||||
Create a user ``testuser1`` in IPA::
|
||||
|
||||
[root@client ~]# ipa user-add testuser1 --first Test --last User1
|
||||
----------------------
|
||||
Added user "testuser1"
|
||||
----------------------
|
||||
User login: testuser1
|
||||
First name: Test
|
||||
Last name: User1
|
||||
Full name: Test User1
|
||||
Display name: Test User1
|
||||
Initials: TU
|
||||
Home directory: /home/testuser1
|
||||
GECOS: Test User1
|
||||
Login shell: /bin/sh
|
||||
Principal name: testuser1@ipademo.local
|
||||
Principal alias: testuser1@ipademo.local
|
||||
Email address: testuser1@ipademo.local
|
||||
UID: 35000003
|
||||
GID: 35000003
|
||||
Password: False
|
||||
Member of groups: ipausers
|
||||
Kerberos keys available: False
|
||||
|
||||
Once user is added, associate it with ``keycloak`` IdP reference we just
|
||||
created. In order to allow user to login via IdP we need few conditions to be
|
||||
satisfied:
|
||||
|
||||
* IdP reference defined for this IdP in IPA
|
||||
* IdP reference associated with the user (``--idp`` option to ``ipa user-add``
|
||||
or ``ipa user-mod``)
|
||||
* IdP identity for the user is set in the user entry (``--idp-user-id`` option
|
||||
to ``ipa user-add`` or ``ipa user-mod``)
|
||||
* finally, user should be allowed to use ``idp`` user authentication method
|
||||
(``--user-auth-type=idp`` option to ``ipa user-add`` or ``ipa user-mod`` or
|
||||
``idp`` method set globally)
|
||||
|
||||
We can set these options to ``testuser1`` with ``ipa user-mod`` command::
|
||||
|
||||
[root@client ~]# ipa user-mod testuser1 --idp keycloak \
|
||||
--idp-user-id testuser1@ipademo.local \
|
||||
--user-auth-type=idp
|
||||
-------------------------
|
||||
Modified user "testuser1"
|
||||
-------------------------
|
||||
User login: testuser1
|
||||
First name: Test
|
||||
Last name: User1
|
||||
Home directory: /home/testuser1
|
||||
Login shell: /bin/sh
|
||||
Principal name: testuser1@ipademo.local
|
||||
Principal alias: testuser1@ipademo.local
|
||||
Email address: testuser1@ipademo.local
|
||||
UID: 35000003
|
||||
GID: 35000003
|
||||
User authentication types: idp
|
||||
External IdP configuration: keycloak
|
||||
External IdP user identifier: testuser1@ipademo.local
|
||||
Account disabled: False
|
||||
Password: False
|
||||
Member of groups: ipausers
|
||||
Kerberos keys available: False
|
||||
|
||||
As can be seen in the output, the account for ``testuser1`` has no password and
|
||||
no Kerberos keys. It will not be able to authenticate to IPA services without
|
||||
IdP's help.
|
||||
|
||||
Access IPA resources as an IdP user
|
||||
-----------------------------------
|
||||
|
||||
There are two ways to trigger authentication and authorization of ``testuser1``
|
||||
via our Keycloak IdP instance:
|
||||
|
||||
* obtain Kerberos ticket with ``kinit`` tool
|
||||
* login to the target system via SSH or on the console
|
||||
|
||||
In order to obtain initial Kerberos ticket, we need to use ``kinit`` tool. SSSD
|
||||
2.7.0 provides a special package ``sssd-idp`` which implements Kerberos
|
||||
pre-authentication method ``idp``. When this package is installed, MIT Kerberos
|
||||
configuration on the host is updated to automatically allow use of ``idp``
|
||||
method. However, ``idp`` method requires use of FAST channel in order to provide
|
||||
a secure connection between the Kerberos client and KDC. This is similar to
|
||||
``otp`` pre-authentication method FreeIPA already provided for several years.
|
||||
When IPA is deployed with integrated CA, IPA also provides a way to obtain a
|
||||
special ticket, called Anonymous PKINIT, to use as a FAST channel factor.
|
||||
|
||||
Let's use Anonymous PKINIT to obtain a ticket and store it in the file
|
||||
``./fast.ccache``. Then we can enable FAST channel with the use of ``-T`` option
|
||||
for ``kinit`` tool::
|
||||
|
||||
[root@client ~]# kinit -n -c ./fast.ccache
|
||||
[root@client ~]# kinit -T ./fast.ccache testuser1
|
||||
Authenticate at https://client.ipademo.local:8443/auth/realms/master/device?user_code=YHMQ-XKTL and press ENTER.:
|
||||
|
||||
The prompt indicates that ``idp`` method was chosen between the KDC and the
|
||||
Kerberos client. When KDC received the initial ticket granting ticket request,
|
||||
IPA database driver (KDB) performed an LDAP lookup of the Kerberos principal and
|
||||
found out that ``testuser1@IPADEMO.LOCAL`` Kerberos principal has ``idp`` user
|
||||
authentication type. This, in turn, activated KDC side of the ``idp``
|
||||
pre-authentication method and led to a request to ``ipa-otpd`` daemon. Finally,
|
||||
``ipa-otpd`` daemon asked ``oidc_child`` to request a device code authorization
|
||||
grant from the IdP associated with the ``testuser1@IPADEMO.LOCAL`` principal.
|
||||
The grant flow resulted in IdP returning a code and a message which was
|
||||
propagated back to the Kerberos client and displayed by the client side of the
|
||||
``idp`` pre-authentication method.
|
||||
|
||||
At this point we need to visit the page and authorize access to the information.
|
||||
Once it is done, we complete the process by pressing ``<ENTER>`` key. If
|
||||
authorization was granted, KDC will issue a Kerberos ticket to and it will be
|
||||
stored in the credentials cache::
|
||||
|
||||
[root@client ~]# klist
|
||||
Ticket cache: KCM:0:58420
|
||||
Default principal: testuser1@IPADEMO.LOCAL
|
||||
|
||||
Valid starting Expires Service principal
|
||||
05/09/22 07:48:23 05/10/22 07:03:07 krbtgt/IPADEMO.LOCAL@IPADEMO.LOCAL
|
||||
|
||||
|
||||
Similar process happens when ``pam_sss`` PAM module is used, for example, to
|
||||
authenticate and authorize access to PAM services. Applications which use PAM to
|
||||
authenticate and authorize remote access can also benefit from the flow. For
|
||||
example, SSH daemon can be configured with ``keyboard-interactive`` method which
|
||||
will allow PAM authentication and authorization. As part of it, PAM messages
|
||||
will be relayed to the SSH client and SSH client's user input will be sent back
|
||||
to PAM::
|
||||
|
||||
$ ssh testuser1@client.ipademo.local
|
||||
(testuser1@client.ipademo.local) Authenticate at https://client.ipademo.local:8443/auth/realms/master/device?user_code=XYFL-ROYR and press ENTER.
|
||||
Last login: Mon May 9 07:48:25 2022 from 10.0.190.227
|
||||
-sh-5.1$ klist
|
||||
Ticket cache: KCM:7800003:58420
|
||||
Default principal: testuser1@IPADEMO.LOCAL
|
||||
|
||||
Valid starting Expires Service principal
|
||||
05/09/22 07:49:38 05/10/22 07:49:24 krbtgt/IPADEMO.LOCAL@IPADEMO.LOCAL
|
||||
-sh-5.1$
|
||||
|
||||
Once initial Kerberos ticket is available, it can be used to perform normal IPA
|
||||
operations:
|
||||
|
||||
- access IPA API with command line tool ``ipa`` or through a Web UI in a browser
|
||||
- login to other systems with GSSAPI authentication
|
||||
- access PAM services which use ``pam_sss_gss`` module in their PAM stack definitions
|
||||
|
||||
Direct authentication to Web UI with the help of OAuth 2.0 client is not implemented yet.
|
||||
|
||||
Troubleshooting IdP integration
|
||||
-------------------------------
|
||||
|
||||
Communication with an IdP server happens on IPA server when KDC calls out to
|
||||
``ipa-otpd`` daemon and ``ipa-otpd`` daemon launches ``oidc_child`` helper.
|
||||
Journal logs for ``ipa-otpd`` can be checked with the ``journalctl`` tool.
|
||||
``ipa-otpd`` processes start on demand and content from all sessions can be
|
||||
captured with the following command::
|
||||
|
||||
[root@master #] journalctl -u 'ipa-otpd@*'
|
||||
|
||||
The output would look similar to the following real world example::
|
||||
|
||||
May 02 18:51:28 dc.ipa.test systemd[1]: Started ipa-otpd service (PID 1473660/UID 0).
|
||||
May 02 18:51:28 dc.ipa.test ipa-otpd[1636136]: LDAP: ldapi://%2Frun%2Fslapd-IPA-TEST.socket
|
||||
May 02 18:51:28 dc.ipa.test ipa-otpd[1636136]: ab@IPA.TEST: request received
|
||||
May 02 18:51:28 dc.ipa.test ipa-otpd[1636136]: ab@IPA.TEST: user query start
|
||||
May 02 18:51:28 dc.ipa.test ipa-otpd[1636136]: ab@IPA.TEST: user query end: uid=ab,cn=users,cn=accounts,dc=ipa,dc=test
|
||||
May 02 18:51:28 dc.ipa.test ipa-otpd[1636136]: ab@IPA.TEST: idp query start: cn=github,cn=idp,dc=ipa,dc=test
|
||||
May 02 18:51:28 dc.ipa.test ipa-otpd[1636136]: ab@IPA.TEST: idp query end: github
|
||||
May 02 18:51:28 dc.ipa.test ipa-otpd[1636136]: ab@IPA.TEST: oauth2 start: Get device code
|
||||
May 02 18:51:29 dc.ipa.test ipa-otpd[1636136]: ab@IPA.TEST: Received: [{"device_code":"f071833afe966eaf596d83646f55250cfdb57418","expires_in":899,"interval":5}
|
||||
May 02 18:51:29 dc.ipa.test ipa-otpd[1636136]: oauth2 {"verification_uri": "https://github.com/login/device", "user_code": "ECD3-4310"}
|
||||
May 02 18:51:29 dc.ipa.test ipa-otpd[1636136]: ]
|
||||
May 02 18:51:29 dc.ipa.test ipa-otpd[1636136]: ab@IPA.TEST: sent: 0 data: 200
|
||||
May 02 18:51:29 dc.ipa.test ipa-otpd[1636136]: ab@IPA.TEST: ..sent: 200 data: 200
|
||||
May 02 18:51:29 dc.ipa.test ipa-otpd[1636136]: ab@IPA.TEST: response sent: Access-Challenge
|
||||
May 02 18:51:29 dc.ipa.test ipa-otpd[1636136]: Socket closed, shutting down...
|
||||
|
||||
First part of the output until ``idp query start`` is similar to RADIUS proxy
|
||||
operation. Unlike RADIUS proxy, in the case of IdP communication, ``ipa-otpd``
|
||||
first receives an initial state from the ``oidc_child`` process and sends it
|
||||
back to the KDC within a RADIUS packet with ``Access-Challenge`` message.
|
||||
|
||||
The state is then transferred to the Kerberos client and results in a message
|
||||
that instructs to visit the verification URI and enter the code. Some IdPs also
|
||||
return a complete message to show, like in the case of Keycloak in our examples
|
||||
above.
|
||||
|
||||
Once the Kerberos client returns, another ``ipa-otpd`` call is performed,
|
||||
this time to request an access token::
|
||||
|
||||
May 02 18:51:50 dc.ipa.test systemd[1]: Started ipa-otpd service (PID 1473661/UID 0).
|
||||
May 02 18:51:50 dc.ipa.test ipa-otpd[1636149]: LDAP: ldapi://%2Frun%2Fslapd-IPA-TEST.socket
|
||||
May 02 18:51:50 dc.ipa.test ipa-otpd[1636149]: ab@IPA.TEST: request received
|
||||
May 02 18:51:50 dc.ipa.test ipa-otpd[1636149]: ab@IPA.TEST: user query start
|
||||
May 02 18:51:50 dc.ipa.test ipa-otpd[1636149]: ab@IPA.TEST: user query end: uid=ab,cn=users,cn=accounts,dc=ipa,dc=test
|
||||
May 02 18:51:50 dc.ipa.test ipa-otpd[1636149]: ab@IPA.TEST: idp query start: cn=github,cn=idp,dc=ipa,dc=test
|
||||
May 02 18:51:50 dc.ipa.test ipa-otpd[1636149]: ab@IPA.TEST: idp query end: github
|
||||
May 02 18:51:50 dc.ipa.test ipa-otpd[1636149]: ab@IPA.TEST: oauth2 start: Get access token
|
||||
May 02 18:51:50 dc.ipa.test ipa-otpd[1636149]: ab@IPA.TEST: Received: [abbra]
|
||||
May 02 18:51:50 dc.ipa.test ipa-otpd[1636149]: ab@IPA.TEST: sent: 0 data: 20
|
||||
May 02 18:51:50 dc.ipa.test ipa-otpd[1636149]: ab@IPA.TEST: ..sent: 20 data: 20
|
||||
May 02 18:51:50 dc.ipa.test ipa-otpd[1636149]: ab@IPA.TEST: response sent: Access-Accept
|
||||
May 02 18:51:50 dc.ipa.test ipa-otpd[1636149]: Socket closed, shutting down...
|
||||
|
||||
An access token request followed by the request to obtain a user information.
|
||||
The resource owner's subject then compared with the value set in the LDAP entry
|
||||
for this Kerberos principal with the help of ``--idp-user-id`` option. Subject's
|
||||
field name is chosen through the same option to the IdP reference. If the check
|
||||
is successful, ``ipa-otpd`` sends a RADIUS packet with ``Access-Accept``
|
||||
response code.
|
||||
|
||||
Communication performed by ``oidc_child`` is not included into the journal logs
|
||||
by default. If there are issues in accessing IdPs, a special option can be added
|
||||
to ``/etc/ipa/default.conf`` to increase log level of ``oidc_child`` output. By
|
||||
default, it is 0 and could be any number between 0 and 10::
|
||||
|
||||
[global]
|
||||
oidc_child_debug_level=10
|
||||
|
||||
A value greater than 6 would include debug output from the ``libcurl`` utility::
|
||||
|
||||
May 02 18:51:50 dc.ipa.test oidc_child[1636150]: oidc_child started.
|
||||
May 02 18:51:50 dc.ipa.test oidc_child[1636150]: Running with effective IDs: [0][0].
|
||||
May 02 18:51:50 dc.ipa.test oidc_child[1636150]: Running with real IDs [0][0].
|
||||
May 02 18:51:50 dc.ipa.test oidc_child[1636150]: JSON device code: [{"device_code":"f071833afe966eaf596d83646f55250cfdb57418","expires_in":899,"interval":5}].
|
||||
May 02 18:51:50 dc.ipa.test oidc_child[1636150]: Result does not contain the 'user_code' string.
|
||||
May 02 18:51:50 dc.ipa.test oidc_child[1636150]: Result does not contain the 'verification_uri' string.
|
||||
May 02 18:51:50 dc.ipa.test oidc_child[1636150]: Result does not contain the 'verification_url' string.
|
||||
May 02 18:51:50 dc.ipa.test oidc_child[1636150]: Result does not contain the 'verification_uri_complete' string.
|
||||
May 02 18:51:50 dc.ipa.test oidc_child[1636150]: Result does not contain the 'message' string.
|
||||
May 02 18:51:50 dc.ipa.test oidc_child[1636150]: device_code: [f071833afe966eaf596d83646f55250cfdb57418].
|
||||
May 02 18:51:50 dc.ipa.test oidc_child[1636150]: expires_in: [899].
|
||||
May 02 18:51:50 dc.ipa.test oidc_child[1636150]: interval: [5].
|
||||
May 02 18:51:50 dc.ipa.test oidc_child[1636150]: POST data: [grant_type=urn:ietf:params:oauth:grant-type:device_code&client_id=some-client-id&device_code=f071833afe966eaf596d83646f55250cfdb57418].
|
||||
May 02 18:51:50 dc.ipa.test oidc_child[1636150]: libcurl: * Trying 140.82.121.3:443...
|
||||
May 02 18:51:50 dc.ipa.test oidc_child[1636150]: libcurl: * Connected to github.com (140.82.121.3) port 443 (#0)
|
||||
May 02 18:51:50 dc.ipa.test oidc_child[1636150]: libcurl: * ALPN, offering h2
|
||||
May 02 18:51:50 dc.ipa.test oidc_child[1636150]: libcurl: * ALPN, offering http/1.1
|
||||
May 02 18:51:50 dc.ipa.test oidc_child[1636150]: libcurl: * successfully set certificate verify locations:
|
||||
May 02 18:51:50 dc.ipa.test oidc_child[1636150]: libcurl: * CAfile: /etc/pki/tls/certs/ca-bundle.crt
|
||||
May 02 18:51:50 dc.ipa.test oidc_child[1636150]: libcurl: * CApath: none
|
||||
May 02 18:51:50 dc.ipa.test oidc_child[1636150]: libcurl: * TLSv1.3 (OUT), TLS handshake, Client hello (1):
|
||||
May 02 18:51:50 dc.ipa.test oidc_child[1636150]: libcurl: * TLSv1.3 (IN), TLS handshake, Server hello (2):
|
||||
May 02 18:51:50 dc.ipa.test oidc_child[1636150]: libcurl: * TLSv1.3 (IN), TLS handshake, Encrypted Extensions (8):
|
||||
May 02 18:51:50 dc.ipa.test oidc_child[1636150]: libcurl: * TLSv1.3 (IN), TLS handshake, Certificate (11):
|
||||
May 02 18:51:50 dc.ipa.test oidc_child[1636150]: libcurl: * TLSv1.3 (IN), TLS handshake, CERT verify (15):
|
||||
May 02 18:51:50 dc.ipa.test oidc_child[1636150]: libcurl: * TLSv1.3 (IN), TLS handshake, Finished (20):
|
||||
May 02 18:51:50 dc.ipa.test oidc_child[1636150]: libcurl: * TLSv1.3 (OUT), TLS change cipher, Change cipher spec (1):
|
||||
May 02 18:51:50 dc.ipa.test oidc_child[1636150]: libcurl: * TLSv1.3 (OUT), TLS handshake, Finished (20):
|
||||
May 02 18:51:50 dc.ipa.test oidc_child[1636150]: libcurl: * SSL connection using TLSv1.3 / TLS_AES_128_GCM_SHA256
|
||||
May 02 18:51:50 dc.ipa.test oidc_child[1636150]: libcurl: * ALPN, server accepted to use h2
|
||||
May 02 18:51:50 dc.ipa.test oidc_child[1636150]: libcurl: * Server certificate:
|
||||
May 02 18:51:50 dc.ipa.test oidc_child[1636150]: libcurl: * subject: C=US; ST=California; L=San Francisco; O=GitHub, Inc.; CN=github.com
|
||||
May 02 18:51:50 dc.ipa.test oidc_child[1636150]: libcurl: * start date: Mar 15 00:00:00 2022 GMT
|
||||
May 02 18:51:50 dc.ipa.test oidc_child[1636150]: libcurl: * expire date: Mar 15 23:59:59 2023 GMT
|
||||
May 02 18:51:50 dc.ipa.test oidc_child[1636150]: libcurl: * subjectAltName: host "github.com" matched cert's "github.com"
|
||||
May 02 18:51:50 dc.ipa.test oidc_child[1636150]: libcurl: * issuer: C=US; O=DigiCert Inc; CN=DigiCert TLS Hybrid ECC SHA384 2020 CA1
|
||||
May 02 18:51:50 dc.ipa.test oidc_child[1636150]: libcurl: * SSL certificate verify ok.
|
||||
May 02 18:51:50 dc.ipa.test oidc_child[1636150]: libcurl: * Using HTTP2, server supports multiplexing
|
||||
May 02 18:51:50 dc.ipa.test oidc_child[1636150]: libcurl: * Connection state changed (HTTP/2 confirmed)
|
||||
May 02 18:51:50 dc.ipa.test oidc_child[1636150]: libcurl: * Copying HTTP/2 data in stream buffer to connection buffer after upgrade: len=0
|
||||
May 02 18:51:50 dc.ipa.test oidc_child[1636150]: libcurl: * Using Stream ID: 1 (easy handle 0x562cd1ee96e0)
|
||||
May 02 18:51:50 dc.ipa.test oidc_child[1636150]: libcurl: > POST /login/oauth/access_token HTTP/2
|
||||
Host: github.com
|
||||
user-agent: SSSD oidc_child/0.0
|
||||
accept: application/json
|
||||
content-length: 139
|
||||
content-type: application/x-www-form-urlencoded
|
||||
May 02 18:51:50 dc.ipa.test oidc_child[1636150]: libcurl: * We are completely uploaded and fine
|
||||
May 02 18:51:50 dc.ipa.test oidc_child[1636150]: libcurl: * TLSv1.3 (IN), TLS handshake, Newsession Ticket (4):
|
||||
May 02 18:51:50 dc.ipa.test oidc_child[1636150]: libcurl: * TLSv1.3 (IN), TLS handshake, Newsession Ticket (4):
|
||||
May 02 18:51:50 dc.ipa.test oidc_child[1636150]: libcurl: * old SSL session ID is stale, removing
|
||||
May 02 18:51:50 dc.ipa.test oidc_child[1636150]: libcurl: < HTTP/2 200
|
||||
May 02 18:51:50 dc.ipa.test oidc_child[1636150]: libcurl: < server: GitHub.com
|
||||
May 02 18:51:50 dc.ipa.test oidc_child[1636150]: libcurl: < date: Mon, 02 May 2022 18:51:50 GMT
|
||||
May 02 18:51:50 dc.ipa.test oidc_child[1636150]: libcurl: < content-type: application/json; charset=utf-8
|
||||
May 02 18:51:50 dc.ipa.test oidc_child[1636150]: libcurl: < vary: X-PJAX, X-PJAX-Container
|
||||
May 02 18:51:50 dc.ipa.test oidc_child[1636150]: libcurl: < permissions-policy: interest-cohort=()
|
||||
May 02 18:51:50 dc.ipa.test oidc_child[1636150]: libcurl: < etag: W/"some-e-tag-value"
|
||||
May 02 18:51:50 dc.ipa.test oidc_child[1636150]: libcurl: < cache-control: max-age=0, private, must-revalidate
|
||||
May 02 18:51:50 dc.ipa.test oidc_child[1636150]: libcurl: < strict-transport-security: max-age=31536000; includeSubdomains; preload
|
||||
May 02 18:51:50 dc.ipa.test oidc_child[1636150]: libcurl: < x-frame-options: deny
|
||||
May 02 18:51:50 dc.ipa.test oidc_child[1636150]: libcurl: < x-content-type-options: nosniff
|
||||
May 02 18:51:50 dc.ipa.test oidc_child[1636150]: libcurl: < x-xss-protection: 0
|
||||
May 02 18:51:50 dc.ipa.test oidc_child[1636150]: libcurl: < referrer-policy: origin-when-cross-origin, strict-origin-when-cross-origin
|
||||
May 02 18:51:50 dc.ipa.test oidc_child[1636150]: libcurl: < expect-ct: max-age=2592000, report-uri="https://api.github.com/_private/browser/errors"
|
||||
May 02 18:51:50 dc.ipa.test oidc_child[1636150]: libcurl: < content-security-policy: default-src 'none'; base-uri 'self'; block-all-mixed-content; child-src github.com/assets-cdn/worker/ gist.github.com/assets-cdn/worker/; connect-src 'self' uploads.git>
|
||||
May 02 18:51:50 dc.ipa.test oidc_child[1636150]: libcurl: < vary: Accept-Encoding, Accept, X-Requested-With
|
||||
May 02 18:51:50 dc.ipa.test oidc_child[1636150]: libcurl: < x-github-request-id: D1EA:541D:48A585:4BF8E5:62702846
|
||||
May 02 18:51:50 dc.ipa.test oidc_child[1636150]: libcurl: <
|
||||
May 02 18:51:50 dc.ipa.test oidc_child[1636150]: {"access_token":"some-access-token","token_type":"bearer","scope":"user"}
|
||||
May 02 18:51:50 dc.ipa.test oidc_child[1636150]: libcurl: * Connection #0 to host github.com left intact
|
||||
May 02 18:51:50 dc.ipa.test oidc_child[1636150]: Result does not contain the 'id_token' string.
|
||||
May 02 18:51:50 dc.ipa.test oidc_child[1636150]: access_token: [some-access-token].
|
||||
May 02 18:51:50 dc.ipa.test oidc_child[1636150]: id_token: [(null)].
|
||||
May 02 18:51:50 dc.ipa.test oidc_child[1636150]: libcurl: * Trying 140.82.121.6:443...
|
||||
May 02 18:51:50 dc.ipa.test oidc_child[1636150]: libcurl: * Connected to api.github.com (140.82.121.6) port 443 (#0)
|
||||
May 02 18:51:50 dc.ipa.test oidc_child[1636150]: libcurl: * ALPN, offering h2
|
||||
May 02 18:51:50 dc.ipa.test oidc_child[1636150]: libcurl: * ALPN, offering http/1.1
|
||||
May 02 18:51:50 dc.ipa.test oidc_child[1636150]: libcurl: * successfully set certificate verify locations:
|
||||
May 02 18:51:50 dc.ipa.test oidc_child[1636150]: libcurl: * CAfile: /etc/pki/tls/certs/ca-bundle.crt
|
||||
May 02 18:51:50 dc.ipa.test oidc_child[1636150]: libcurl: * CApath: none
|
||||
May 02 18:51:50 dc.ipa.test oidc_child[1636150]: libcurl: * TLSv1.3 (OUT), TLS handshake, Client hello (1):
|
||||
May 02 18:51:50 dc.ipa.test oidc_child[1636150]: libcurl: * TLSv1.3 (IN), TLS handshake, Server hello (2):
|
||||
May 02 18:51:50 dc.ipa.test oidc_child[1636150]: libcurl: * TLSv1.3 (IN), TLS handshake, Encrypted Extensions (8):
|
||||
May 02 18:51:50 dc.ipa.test oidc_child[1636150]: libcurl: * TLSv1.3 (IN), TLS handshake, Certificate (11):
|
||||
May 02 18:51:50 dc.ipa.test oidc_child[1636150]: libcurl: * TLSv1.3 (IN), TLS handshake, CERT verify (15):
|
||||
May 02 18:51:50 dc.ipa.test oidc_child[1636150]: libcurl: * TLSv1.3 (IN), TLS handshake, Finished (20):
|
||||
May 02 18:51:50 dc.ipa.test oidc_child[1636150]: libcurl: * TLSv1.3 (OUT), TLS change cipher, Change cipher spec (1):
|
||||
May 02 18:51:50 dc.ipa.test oidc_child[1636150]: libcurl: * TLSv1.3 (OUT), TLS handshake, Finished (20):
|
||||
May 02 18:51:50 dc.ipa.test oidc_child[1636150]: libcurl: * SSL connection using TLSv1.3 / TLS_AES_128_GCM_SHA256
|
||||
May 02 18:51:50 dc.ipa.test oidc_child[1636150]: libcurl: * ALPN, server accepted to use h2
|
||||
May 02 18:51:50 dc.ipa.test oidc_child[1636150]: libcurl: * Server certificate:
|
||||
May 02 18:51:50 dc.ipa.test oidc_child[1636150]: libcurl: * subject: C=US; ST=California; L=San Francisco; O=GitHub, Inc.; CN=*.github.com
|
||||
May 02 18:51:50 dc.ipa.test oidc_child[1636150]: libcurl: * start date: Mar 16 00:00:00 2022 GMT
|
||||
May 02 18:51:50 dc.ipa.test oidc_child[1636150]: libcurl: * expire date: Mar 16 23:59:59 2023 GMT
|
||||
May 02 18:51:50 dc.ipa.test oidc_child[1636150]: libcurl: * subjectAltName: host "api.github.com" matched cert's "*.github.com"
|
||||
May 02 18:51:50 dc.ipa.test oidc_child[1636150]: libcurl: * issuer: C=US; O=DigiCert Inc; CN=DigiCert TLS Hybrid ECC SHA384 2020 CA1
|
||||
May 02 18:51:50 dc.ipa.test oidc_child[1636150]: libcurl: * SSL certificate verify ok.
|
||||
May 02 18:51:50 dc.ipa.test oidc_child[1636150]: libcurl: * Using HTTP2, server supports multiplexing
|
||||
May 02 18:51:50 dc.ipa.test oidc_child[1636150]: libcurl: * Connection state changed (HTTP/2 confirmed)
|
||||
May 02 18:51:50 dc.ipa.test oidc_child[1636150]: libcurl: * Copying HTTP/2 data in stream buffer to connection buffer after upgrade: len=0
|
||||
May 02 18:51:50 dc.ipa.test oidc_child[1636150]: libcurl: * Server auth using Bearer with user ''
|
||||
May 02 18:51:50 dc.ipa.test oidc_child[1636150]: libcurl: * Using Stream ID: 1 (easy handle 0x562cd1f92ae0)
|
||||
May 02 18:51:50 dc.ipa.test oidc_child[1636150]: libcurl: > GET /user HTTP/2
|
||||
Host: api.github.com
|
||||
authorization: Bearer some-token-value
|
||||
user-agent: SSSD oidc_child/0.0
|
||||
accept: application/json
|
||||
May 02 18:51:50 dc.ipa.test oidc_child[1636150]: libcurl: * TLSv1.3 (IN), TLS handshake, Newsession Ticket (4):
|
||||
May 02 18:51:50 dc.ipa.test oidc_child[1636150]: libcurl: * TLSv1.3 (IN), TLS handshake, Newsession Ticket (4):
|
||||
May 02 18:51:50 dc.ipa.test oidc_child[1636150]: libcurl: * old SSL session ID is stale, removing
|
||||
May 02 18:51:50 dc.ipa.test oidc_child[1636150]: libcurl: < HTTP/2 200
|
||||
May 02 18:51:50 dc.ipa.test oidc_child[1636150]: libcurl: < server: GitHub.com
|
||||
May 02 18:51:50 dc.ipa.test oidc_child[1636150]: libcurl: < date: Mon, 02 May 2022 18:51:50 GMT
|
||||
May 02 18:51:50 dc.ipa.test oidc_child[1636150]: libcurl: < content-type: application/json; charset=utf-8
|
||||
May 02 18:51:50 dc.ipa.test oidc_child[1636150]: libcurl: < content-length: 1357
|
||||
May 02 18:51:50 dc.ipa.test oidc_child[1636150]: libcurl: < cache-control: private, max-age=60, s-maxage=60
|
||||
May 02 18:51:50 dc.ipa.test oidc_child[1636150]: libcurl: < vary: Accept, Authorization, Cookie, X-GitHub-OTP
|
||||
May 02 18:51:50 dc.ipa.test oidc_child[1636150]: libcurl: < etag: "some-e-tag-value"
|
||||
May 02 18:51:50 dc.ipa.test oidc_child[1636150]: libcurl: < last-modified: Mon, 14 Mar 2022 14:05:20 GMT
|
||||
May 02 18:51:50 dc.ipa.test oidc_child[1636150]: libcurl: < x-oauth-scopes: user
|
||||
May 02 18:51:50 dc.ipa.test oidc_child[1636150]: libcurl: < x-accepted-oauth-scopes:
|
||||
May 02 18:51:50 dc.ipa.test oidc_child[1636150]: libcurl: < x-oauth-client-id: some-client-id
|
||||
May 02 18:51:50 dc.ipa.test oidc_child[1636150]: libcurl: < x-github-media-type: github.v3
|
||||
May 02 18:51:50 dc.ipa.test oidc_child[1636150]: libcurl: < x-ratelimit-limit: 5000
|
||||
May 02 18:51:50 dc.ipa.test oidc_child[1636150]: libcurl: < x-ratelimit-remaining: 4996
|
||||
May 02 18:51:50 dc.ipa.test oidc_child[1636150]: libcurl: < x-ratelimit-reset: 1651520567
|
||||
May 02 18:51:50 dc.ipa.test oidc_child[1636150]: libcurl: < x-ratelimit-used: 4
|
||||
May 02 18:51:50 dc.ipa.test oidc_child[1636150]: libcurl: < x-ratelimit-resource: core
|
||||
May 02 18:51:50 dc.ipa.test oidc_child[1636150]: libcurl: < access-control-expose-headers: ETag, Link, Location, Retry-After, X-GitHub-OTP, X-RateLimit-Limit, X-RateLimit-Remaining, X-RateLimit-Used, X-RateLimit-Resource, X-RateLimit-Reset, X-OAuth-Scop>
|
||||
May 02 18:51:50 dc.ipa.test oidc_child[1636150]: libcurl: < access-control-allow-origin: *
|
||||
May 02 18:51:50 dc.ipa.test oidc_child[1636150]: libcurl: < strict-transport-security: max-age=31536000; includeSubdomains; preload
|
||||
May 02 18:51:50 dc.ipa.test oidc_child[1636150]: libcurl: < x-frame-options: deny
|
||||
May 02 18:51:50 dc.ipa.test oidc_child[1636150]: libcurl: < x-content-type-options: nosniff
|
||||
May 02 18:51:50 dc.ipa.test oidc_child[1636150]: libcurl: < x-xss-protection: 0
|
||||
May 02 18:51:50 dc.ipa.test oidc_child[1636150]: libcurl: < referrer-policy: origin-when-cross-origin, strict-origin-when-cross-origin
|
||||
May 02 18:51:50 dc.ipa.test oidc_child[1636150]: libcurl: < content-security-policy: default-src 'none'
|
||||
May 02 18:51:50 dc.ipa.test oidc_child[1636150]: libcurl: < vary: Accept-Encoding, Accept, X-Requested-With
|
||||
May 02 18:51:50 dc.ipa.test oidc_child[1636150]: libcurl: < x-github-request-id: C5B8:5B48:4C0EB7:4D8AF2:62702846
|
||||
May 02 18:51:50 dc.ipa.test oidc_child[1636150]: libcurl: <
|
||||
May 02 18:51:50 dc.ipa.test oidc_child[1636150]: {"login":"abbra","id":some-id,"node_id":"some-node","avatar_url":"some-avatar-url","gravatar_id":"","url":"some-user-url","html_ur
|
||||
May 02 18:51:50 dc.ipa.test oidc_child[1636150]: l":"some-url","followers_url":"some-api-url","following_url":"some-following-url","gists_url":"some-gists-url>
|
||||
May 02 18:51:50 dc.ipa.test oidc_child[1636150]: libcurl: * Connection #0 to host api.github.com left intact
|
||||
May 02 18:51:50 dc.ipa.test oidc_child[1636150]: userinfo: [{"login": "abbra", "id": some-id, "node_id": "some-node", "avatar_url": "some-avatar-rul", "gravatar_id": "", "url": "some-user-url", ">
|
||||
May 02 18:51:50 dc.ipa.test oidc_child[1636150]: User identifier: [abbra].
|
||||
May 02 18:51:50 dc.ipa.test oidc_child[1636150]: User identifier: [abbra].
|
||||
May 02 18:51:50 dc.ipa.test oidc_child[1636150]: oidc_child finished successful!
|
||||
|
||||
Don't forget to remove ``oidc_child_debug_level`` from the
|
||||
``/etc/ipa/default.conf`` once troubleshooting is done. Information like above
|
||||
often contains personal details of the user and should probably not stored in
|
||||
the system journal.
|
||||
62
doc/workshop/2-client-install.rst
Normal file
62
doc/workshop/2-client-install.rst
Normal file
@@ -0,0 +1,62 @@
|
||||
.. _2-client-install:
|
||||
|
||||
Unit 2: Enrolling client machines
|
||||
===================================
|
||||
|
||||
**Prerequisites**:
|
||||
|
||||
- :ref:`Unit 1: Installing the FreeIPA server <1-server-install>`
|
||||
|
||||
In this unit, you will enrol a *host* as a client of your FreeIPA
|
||||
domain. This means that *users* in your FreeIPA realm (or Active
|
||||
Directory realms for which there is a trust with FreeIPA) can log
|
||||
into the client machine (subject to access policies) and that *services*
|
||||
on the client can leverage FreeIPA's authentication and
|
||||
authorisation services.
|
||||
|
||||
From the directory that contains the ``Vagrantfile``, SSH into the
|
||||
``client`` machine::
|
||||
|
||||
$ vagrant ssh client
|
||||
|
||||
|
||||
On ``client``, start the FreeIPA client enrolment program::
|
||||
|
||||
[client]$ sudo ipa-client-install --mkhomedir
|
||||
|
||||
The FreeIPA server should be detected through DNS autodiscovery.
|
||||
(If DNS discovery fails, e.g. due to client machine having incorrect
|
||||
``/etc/resolv.conf`` configuration, you would be prompted to
|
||||
manually enter the domain and server hostname instead).
|
||||
|
||||
The autodetected server settings will be displayed; confirm to
|
||||
proceed::
|
||||
|
||||
[client]$ sudo ipa-client-install --mkhomedir
|
||||
Discovery was successful!
|
||||
Client hostname: client.ipademo.local
|
||||
Realm: IPADEMO.LOCAL
|
||||
DNS Domain: ipademo.local
|
||||
IPA Server: server.ipademo.local
|
||||
BaseDN: dc=ipademo,dc=local
|
||||
|
||||
Continue to configure the system with these values? [no]: yes
|
||||
|
||||
Next, the client's time will be synchronised with the server, then
|
||||
the installer will prompt you to enter the credentials of a user
|
||||
authorised to enrol hosts (``admin``)::
|
||||
|
||||
User authorized to enroll computers: admin
|
||||
Password for admin@IPADEMO.LOCAL:
|
||||
|
||||
The enrolment now proceeds; no further input is required. You will
|
||||
see output detailing the operations being completed. Client
|
||||
enrolment only takes a few seconds.
|
||||
|
||||
Users in your FreeIPA domain can now log into FreeIPA-enrolled
|
||||
hosts, subject to *Host-based access control* (HBAC) rules. Users
|
||||
logged onto the host can also acquire Kerberos tickets for accessing
|
||||
*services* in your domain.
|
||||
|
||||
You can now move on to
|
||||
:ref:`Unit 3: User management and Kerberos authentication <3-user-management>`.
|
||||
133
doc/workshop/3-user-management.rst
Normal file
133
doc/workshop/3-user-management.rst
Normal file
@@ -0,0 +1,133 @@
|
||||
.. _3-user-management:
|
||||
|
||||
Unit 3: User management and Kerberos authentication
|
||||
=====================================================
|
||||
|
||||
This unit introduces the ``ipa`` CLI program and the web
|
||||
interface. We will perform some simple administrative tasks: adding
|
||||
groups and users and managing group membership.
|
||||
|
||||
Web UI
|
||||
------
|
||||
|
||||
Visit ``https://server.ipademo.local/``. You'll get a TLS
|
||||
*untrusted issuer* warning which you can dismiss (by adding a temporary
|
||||
exception). Log in as ``admin``.
|
||||
|
||||
Welcome to the FreeIPA Web UI. Most management activities can be
|
||||
performed here, or via the ``ipa`` CLI program. Use the Web UI to
|
||||
perform the following actions:
|
||||
|
||||
1. Add a *User* with the username ``alice``.
|
||||
2. Add a *User Group* for system administrators named ``sysadmin``.
|
||||
3. Add ``alice`` to the ``sysadmin`` group.
|
||||
|
||||
|
||||
CLI
|
||||
---
|
||||
|
||||
Make sure you have a Kerberos ticket for ``admin`` (reminder:
|
||||
``kinit admin``).
|
||||
|
||||
Most FreeIPA administrative actions can be carried out using the
|
||||
``ipa`` CLI program. Let's see what commands are available::
|
||||
|
||||
[server]% ipa help commands
|
||||
automember-add Add an automember rule.
|
||||
automember-add-condition Add conditions to an automember rule.
|
||||
automember-default-group-remove Remove default (fallback) group for all unmatched entries.
|
||||
automember-default-group-set Set default (fallback) group for all unmatched entries.
|
||||
automember-default-group-show Display information about the default (fallback) automember groups.
|
||||
...
|
||||
|
||||
Whoa! There are nearly 400 commands! We'll be using only a handful
|
||||
of these today. Note that command completion is enabled in the
|
||||
shell, so you can type a partial command and press ``<TAB>`` a
|
||||
couple of times to see what commands are available, e.g. all the
|
||||
commands starting with ``cert-``::
|
||||
|
||||
[server]$ ipa cert-<TAB>
|
||||
cert-find cert-request cert-show
|
||||
cert-remove-hold cert-revoke cert-status
|
||||
|
||||
|
||||
You'll notice that commands are grouped by *topic*, or the kind of
|
||||
object they act upon. Run ``ipa help topics`` to list all topics.
|
||||
You can read a general overview of a topic by running ``ipa help
|
||||
<topic>``, and specific information on a particular command by
|
||||
running ``ipa help <command>``.
|
||||
|
||||
Add a user named ``bob`` from the CLI. Use the CLI help to find the
|
||||
right command (**hint**: the ``user`` plugin provides the command).
|
||||
|
||||
|
||||
User authentication
|
||||
-------------------
|
||||
|
||||
We have seen how to authenticate as ``admin``. The process is the
|
||||
same for regular users - just ``kinit <username>``!
|
||||
|
||||
Try to authenticate as ``bob``::
|
||||
|
||||
[server]$ kinit bob
|
||||
kinit: Pre-authentication failed: Invalid argument while getting initial credentials
|
||||
|
||||
If you did *not* encounter this error, congratulations - you must be
|
||||
a disciplined reader of documentation! To set an initial password
|
||||
when creating a user via the ``ipa user-add`` command you must
|
||||
supply the ``--password`` flag (the command will prompt for the
|
||||
password).
|
||||
|
||||
Use the ``ipa passwd`` command to (re)set a user's password::
|
||||
|
||||
[server]$ ipa passwd bob
|
||||
New Password:
|
||||
Enter New Password again to verify:
|
||||
----------------------------------------
|
||||
Changed password for "bob@IPADEMO.LOCAL"
|
||||
----------------------------------------
|
||||
|
||||
Whenever a user has their password reset (including the first time
|
||||
it is set), the next ``kinit`` will prompt them to enter a new
|
||||
password::
|
||||
|
||||
[server]$ kinit bob
|
||||
Password for bob@IPADEMO.LOCAL:
|
||||
Password expired. You must change it now.
|
||||
Enter new password:
|
||||
Enter it again:
|
||||
|
||||
|
||||
Now ``bob`` has a TGT (run ``klist`` to confirm) which he can use to
|
||||
authenticate himself to other hosts and services. Try logging into
|
||||
``client.ipademo.local``::
|
||||
|
||||
[server]$ ssh bob@client.ipademo.local
|
||||
Creating home directory for bob.
|
||||
[bob@client]$
|
||||
|
||||
You are now logged into the client as ``bob``. Type ``^D`` or
|
||||
``exit`` to log out and return to the ``server`` shell. If you run
|
||||
``klist`` again, you will see not only the TGT but a *service ticket*
|
||||
that was automatically acquired to log in to
|
||||
``client.ipademo.local`` without prompting for a password. Kerberos
|
||||
is a true *single sign-on* protocol!
|
||||
|
||||
::
|
||||
|
||||
[server]$ klist
|
||||
Ticket cache: KEYRING:persistent:1000:1000
|
||||
Default principal: bob@IPADEMO.LOCAL
|
||||
|
||||
Valid starting Expires Service principal
|
||||
06/04/2018 21:45:50 06/05/2018 21:38:24 host/client.ipademo.local@IPADEMO.LOCAL
|
||||
06/04/2018 21:38:41 06/05/2018 21:38:24 krbtgt/IPADEMO.LOCAL@IPADEMO.LOCAL
|
||||
|
||||
|
||||
Now that you have created some users, it's time to define some
|
||||
access policies. Proceed to
|
||||
:ref:`Unit 4: Host-based access control (HBAC) <4-hbac>`.
|
||||
|
||||
Alternatively, if you are interested in SSH public key management
|
||||
for users and hosts, jump ahead to
|
||||
:ref:`Unit 10: SSH user and host key management <10-ssh-key-management>`.
|
||||
150
doc/workshop/4-hbac.rst
Normal file
150
doc/workshop/4-hbac.rst
Normal file
@@ -0,0 +1,150 @@
|
||||
.. _4-hbac:
|
||||
|
||||
Unit 4: Host-based access control (HBAC)
|
||||
==========================================
|
||||
|
||||
**Prerequisites:**
|
||||
|
||||
- :ref:`Unit 3: User management and Kerberos authentication <3-user-management>`
|
||||
|
||||
FreeIPA's *host-based access control* (HBAC) feature allows you to
|
||||
define policies that restrict access to hosts or services based on
|
||||
the user attempting to log in and that user's groups, the host that
|
||||
they are trying to access (or its *Host Groups*), and (optionally)
|
||||
the service being accessed.
|
||||
|
||||
In this unit, we will define an HBAC policy that restricts
|
||||
login access to ``client.ipademo.local`` to members of the
|
||||
``sysadmin`` user group.
|
||||
|
||||
|
||||
Adding a host group
|
||||
-------------------
|
||||
|
||||
Instead of defining the HBAC rule to directly talk about
|
||||
``client.ipademo.local``, create a *Host Group* named ``webservers``
|
||||
and add ``client.ipademo.local`` to it. You can do this via the Web
|
||||
UI or the ``ipa`` CLI program (don't forget to ``kinit admin``; see
|
||||
if you can work out what plugin provides the host group
|
||||
functionality).
|
||||
|
||||
**Hint:** if you use the CLI will need to run two separate
|
||||
commands—one to create the host group, then another to add
|
||||
``client.ipademo.local`` to the host group.
|
||||
|
||||
|
||||
Disabling the ``allow_all`` HBAC rule
|
||||
-------------------------------------
|
||||
|
||||
HBAC rules are managed via the ``hbacrule`` plugin. You can
|
||||
complete the following actions via the Web UI as well, but we will
|
||||
cover the CLI commands.
|
||||
|
||||
List the existing HBAC rules::
|
||||
|
||||
[server]$ ipa hbacrule-find
|
||||
-------------------
|
||||
1 HBAC rule matched
|
||||
-------------------
|
||||
Rule name: allow_all
|
||||
User category: all
|
||||
Host category: all
|
||||
Service category: all
|
||||
Description: Allow all users to access any host from any host
|
||||
Enabled: TRUE
|
||||
----------------------------
|
||||
Number of entries returned 1
|
||||
----------------------------
|
||||
|
||||
The FreeIPA server is installed with a single default ``allow_all``
|
||||
rule. This rule must be disabled for other HBAC rules to take
|
||||
effect. Look for a command that can do this, and run it.
|
||||
|
||||
|
||||
Creating HBAC rules
|
||||
-------------------
|
||||
|
||||
HBAC rules are built up incrementally. The rule is created, then
|
||||
users or groups, hosts or hostgroups and HBAC services are added to
|
||||
the rule. The following transcript details the process::
|
||||
|
||||
[server]$ ipa hbacrule-add sysadmin_webservers
|
||||
-------------------------------------
|
||||
Added HBAC rule "sysadmin_webservers"
|
||||
-------------------------------------
|
||||
Rule name: sysadmin_webservers
|
||||
Enabled: TRUE
|
||||
|
||||
[server]$ ipa hbacrule-add-host sysadmin_webservers --hostgroup webservers
|
||||
Rule name: sysadmin_webservers
|
||||
Enabled: TRUE
|
||||
Host Groups: webservers
|
||||
-------------------------
|
||||
Number of members added 1
|
||||
-------------------------
|
||||
|
||||
[server]$ ipa hbacrule-add-user sysadmin_webservers --group sysadmin
|
||||
Rule name: sysadmin_webservers
|
||||
Enabled: TRUE
|
||||
User Groups: sysadmin
|
||||
Host Groups: webservers
|
||||
-------------------------
|
||||
Number of members added 1
|
||||
-------------------------
|
||||
|
||||
[server]$ ipa hbacrule-mod sysadmin_webservers --servicecat=all
|
||||
----------------------------------------
|
||||
Modified HBAC rule "sysadmin_webservers"
|
||||
----------------------------------------
|
||||
Rule name: sysadmin_webservers
|
||||
Service category: all
|
||||
Enabled: TRUE
|
||||
User Groups: sysadmin
|
||||
Host Groups: webservers
|
||||
|
||||
The ``--servicecat=all`` option applies this rule for all services on
|
||||
matching hosts. It could have been set during the ``hbacrule-add``
|
||||
command instead.
|
||||
|
||||
|
||||
Testing HBAC rules
|
||||
------------------
|
||||
|
||||
You can test HBAC rule evaluation using the ``ipa hbactest``
|
||||
command::
|
||||
|
||||
[server]$ ipa hbactest --host client.ipademo.local --service sshd --user bob
|
||||
---------------------
|
||||
Access granted: False
|
||||
---------------------
|
||||
Not matched rules: sysadmin_webservers
|
||||
|
||||
Poor ``bob``. He won't be allowed in because he is not a member of
|
||||
the ``sysadmin`` group. What is the result of ``ipa hbactest`` for
|
||||
``alice``?
|
||||
|
||||
``kinit`` as ``bob`` and try to log in to the client::
|
||||
|
||||
[server]$ kinit bob
|
||||
Password for bob@IPADEMO.LOCAL:
|
||||
[server]$ ssh bob@client.ipademo.local
|
||||
Connection closed by UNKNOWN port 65535
|
||||
|
||||
The server refused to let ``bob`` in and closed the connection.
|
||||
|
||||
Now try ``alice``::
|
||||
|
||||
[server]$ kinit alice
|
||||
Password for alice@IPADEMO.LOCAL:
|
||||
[server]$ ssh alice@client.ipademo.local
|
||||
Creating home directory for alice.
|
||||
[alice@client]$
|
||||
|
||||
|
||||
This was the final mandatory unit in the workshop. From here, there
|
||||
are several optional units you can choose from. You can proceed
|
||||
directly to
|
||||
:ref:`Unit 5: Web application authentication and authorisation <5-web-app-authnz>`.
|
||||
Otherwise,
|
||||
:ref:`return to the curriculum overview <curriculum-overview>`
|
||||
to see all the options.
|
||||
314
doc/workshop/5-web-app-authnz.rst
Normal file
314
doc/workshop/5-web-app-authnz.rst
Normal file
@@ -0,0 +1,314 @@
|
||||
.. _5-web-app-authnz:
|
||||
|
||||
Unit 5: Web application authentication and authorisation
|
||||
==========================================================
|
||||
|
||||
**Prerequisites**:
|
||||
|
||||
- :ref:`Unit 3: User management and Kerberos authentication <3-user-management>`
|
||||
- :ref:`Unit 4: Host-based access control (HBAC) <4-hbac>`
|
||||
|
||||
You can configure many kinds of applications to rely on FreeIPA's
|
||||
centralised authentication, including web applications. In this
|
||||
unit you will configure the Apache web server to use Kerberos
|
||||
authentication to authenticate users, PAM to enforce HBAC rules, and
|
||||
``mod_lookup_identity`` to populate the request environment with
|
||||
user attributes.
|
||||
|
||||
All activities in this unit take place on ``client`` unless
|
||||
otherwise specified. **Access the host via ``vagrant ssh client``**
|
||||
to ensure you have ``sudo`` access.
|
||||
|
||||
The demo web application is trivial. It just reads its request
|
||||
environment and responds in plain text with a list of variables
|
||||
starting with the string ``"REMOTE_"``. It should be up and running
|
||||
already::
|
||||
|
||||
[client]$ curl http://client.ipademo.local
|
||||
NOT LOGGED IN
|
||||
|
||||
REMOTE_* REQUEST VARIABLES:
|
||||
|
||||
REMOTE_ADDR: 192.168.33.20
|
||||
REMOTE_PORT: 34356
|
||||
|
||||
|
||||
Create a service
|
||||
----------------
|
||||
|
||||
Create a *service* representing the web application on
|
||||
``client.ipademo.local``. A service principal name has the service
|
||||
type as its first part, separated from the host name by a slash,
|
||||
e.g. ``HTTP/www.example.com``. The host part must be a host
|
||||
enrolled in FreeIPA.
|
||||
|
||||
You must be getting the hang of FreeIPA by now, so I'll leave the
|
||||
rest of this step up to you. (It's OK to ask for help!)
|
||||
|
||||
|
||||
Retrieve Kerberos keytab
|
||||
------------------------
|
||||
|
||||
The service needs access to its Kerberos key in order to
|
||||
authenticate users. Retrieve the key from the FreeIPA server and
|
||||
store it in a *keytab* file (you will need a TGT for ``admin``)::
|
||||
|
||||
[client]$ ipa-getkeytab -p HTTP/client.ipademo.local -k app.keytab
|
||||
Keytab successfully retrieved and stored in: app.keytab
|
||||
|
||||
We also have to move the file, change its ownership and apply the
|
||||
proper SELinux labels to the keytab file so that the Apache process
|
||||
which runs under the confined ``apache`` user may read it::
|
||||
|
||||
[client]$ sudo mv app.keytab /etc/httpd
|
||||
[client]$ sudo chown apache:apache /etc/httpd/app.keytab
|
||||
[client]$ sudo restorecon /etc/httpd/app.keytab
|
||||
|
||||
|
||||
Enable Kerberos authentication
|
||||
------------------------------
|
||||
|
||||
In this section we will use mod_auth_gssapi_ to enable Kerberos
|
||||
Negotiate / SPNEGO authentication for a web application.
|
||||
|
||||
.. _mod_auth_gssapi: https://github.com/modauthgssapi/mod_auth_gssapi
|
||||
|
||||
The Apache configuration for the demo application lives in the file
|
||||
``/etc/httpd/conf.d/app.conf``. Update the configuration (use
|
||||
``sudo vi`` or ``sudo nano``) to enable Kerberos authentication::
|
||||
|
||||
<VirtualHost *:80>
|
||||
ServerName client.ipademo.local
|
||||
WSGIScriptAlias / /usr/share/httpd/app.py
|
||||
|
||||
<Location />
|
||||
AuthType GSSAPI
|
||||
AuthName "Kerberos Login"
|
||||
GssapiCredStore keytab:/etc/httpd/app.keytab
|
||||
Require valid-user
|
||||
</Location>
|
||||
|
||||
<Directory /usr/share/httpd>
|
||||
<Files "app.py">
|
||||
Require all granted
|
||||
</Files>
|
||||
</Directory>
|
||||
</VirtualHost>
|
||||
|
||||
|
||||
When the configuration is in place, restart Apache::
|
||||
|
||||
[client]$ sudo systemctl restart httpd
|
||||
|
||||
|
||||
To test that Kerberos Negotiate authentication is working, ``kinit``
|
||||
and make a request using ``curl``::
|
||||
|
||||
[client]$ kinit bob
|
||||
Password for bob@IPADEMO.LOCAL:
|
||||
|
||||
[client]$ curl -u : --negotiate http://client.ipademo.local/
|
||||
LOGGED IN AS: bob@IPADEMO.LOCAL
|
||||
|
||||
REMOTE_* REQUEST VARIABLES:
|
||||
|
||||
REMOTE_ADDR: 192.168.33.20
|
||||
REMOTE_USER: bob@IPADEMO.LOCAL
|
||||
REMOTE_PORT: 42499
|
||||
|
||||
The ``REMOTE_USER`` variable in the request environment indicates
|
||||
that there is an authenticated user, and identifies that user.
|
||||
|
||||
|
||||
Populating request environment with user attributes
|
||||
----------------------------------------------------
|
||||
|
||||
Applications need to know more than just the username of a logged-in
|
||||
user. They want to know the user's name, to send mail to their email
|
||||
address and perhaps to know their group memberships or other
|
||||
attributes. In this section, we will use mod_lookup_identity_ to
|
||||
populate the HTTP request environment with variables providing
|
||||
information about the authenticated user.
|
||||
|
||||
.. _mod_lookup_identity: https://www.adelton.com/apache/mod_lookup_identity/
|
||||
|
||||
``mod_lookup_identity`` retrieves user attributes from SSSD (via D-Bus).
|
||||
Edit ``/etc/sssd/sssd.conf``; enable the SSSD ``ifp`` *InfoPipe*
|
||||
responder, permit the ``apache`` user to query it, and configure the
|
||||
attributes that you want to expose. Add the following configuration to
|
||||
``sssd.conf``::
|
||||
|
||||
[domain/ipademo.local]
|
||||
...
|
||||
ldap_user_extra_attrs = mail, givenname, sn
|
||||
|
||||
[sssd]
|
||||
services = nss, sudo, pam, ssh, ifp
|
||||
...
|
||||
|
||||
[ifp]
|
||||
allowed_uids = apache, root
|
||||
user_attributes = +mail, +givenname, +sn
|
||||
|
||||
|
||||
Restart SSSD::
|
||||
|
||||
[client]$ sudo systemctl restart sssd
|
||||
|
||||
If you had not added an email address to your users when you created them, you will need to empty the SSSD cache::
|
||||
|
||||
[client]$ sudo sss_cache -E
|
||||
|
||||
|
||||
You can test the SSSD InfoPipe directly via the ``dbus-send``
|
||||
utility::
|
||||
|
||||
[client]$ sudo dbus-send --print-reply --system \
|
||||
--dest=org.freedesktop.sssd.infopipe /org/freedesktop/sssd/infopipe \
|
||||
org.freedesktop.sssd.infopipe.GetUserAttr string:alice array:string:mail
|
||||
method return time=1528050430.867333 sender=:1.147 -> destination=:1.150 serial=5 reply_serial=2
|
||||
array [
|
||||
dict entry(
|
||||
string "mail"
|
||||
variant array [
|
||||
string "alice@ipademo.local"
|
||||
]
|
||||
)
|
||||
]
|
||||
|
||||
|
||||
Now update the Apache configuration to populate the request
|
||||
environment. The ``LookupUserXXX`` directives define the mapping of
|
||||
user attributes to request environment variables. Multi-valued
|
||||
attributes can be expanded into multiple variables, as in the
|
||||
``LookupUserGroupsIter`` directive. Do not forget the
|
||||
``LoadModule`` directive at the top!
|
||||
|
||||
::
|
||||
|
||||
LoadModule lookup_identity_module modules/mod_lookup_identity.so
|
||||
|
||||
<VirtualHost *:80>
|
||||
ServerName client.ipademo.local
|
||||
WSGIScriptAlias / /usr/share/httpd/app.py
|
||||
|
||||
<Location />
|
||||
AuthType GSSAPI
|
||||
AuthName "Kerberos Login"
|
||||
GssapiCredStore keytab:/etc/httpd/app.keytab
|
||||
Require valid-user
|
||||
|
||||
LookupUserAttr mail REMOTE_USER_MAIL
|
||||
LookupUserAttr givenname REMOTE_USER_FIRSTNAME
|
||||
LookupUserAttr sn REMOTE_USER_LASTNAME
|
||||
LookupUserGroupsIter REMOTE_USER_GROUP
|
||||
</Location>
|
||||
|
||||
...
|
||||
</VirtualHost>
|
||||
|
||||
Default SELinux policy prevents Apache from communicating with SSSD
|
||||
over D-Bus. Set ``httpd_dbus_sssd`` to ``1``::
|
||||
|
||||
[client]$ sudo setsebool -P httpd_dbus_sssd 1
|
||||
|
||||
Restart Apache::
|
||||
|
||||
[client]$ sudo systemctl restart httpd
|
||||
|
||||
Now make another request to the application and observe that user
|
||||
information that was injected into the request environment by
|
||||
``mod_lookup_identity`` is reflected in the response::
|
||||
|
||||
[client]$ curl -u : --negotiate http://client.ipademo.local/
|
||||
LOGGED IN AS: alice@IPADEMO.LOCAL
|
||||
|
||||
REMOTE_* REQUEST VARIABLES:
|
||||
|
||||
REMOTE_USER_GROUP_N: 2
|
||||
REMOTE_ADDR: 192.168.33.20
|
||||
REMOTE_USER_FIRSTNAME: Alice
|
||||
REMOTE_USER_LASTNAME: Able
|
||||
REMOTE_USER: alice@IPADEMO.LOCAL
|
||||
REMOTE_USER_GROUP_2: ipausers
|
||||
REMOTE_USER_GROUP_1: sysadmin
|
||||
REMOTE_PORT: 42586
|
||||
REMOTE_USER_EMAIL: alice@ipademo.local
|
||||
|
||||
|
||||
HBAC for web services
|
||||
---------------------
|
||||
|
||||
The final task for this unit is to configure Apache to use FreeIPA's HBAC
|
||||
rules for access control. We will use mod_authnz_pam_ in
|
||||
conjunction with SSSD's PAM responder to achieve this.
|
||||
|
||||
.. _mod_authnz_pam: http://www.adelton.com/apache/mod_authnz_pam/
|
||||
|
||||
First add an *HBAC service* named ``app`` for the web application.
|
||||
You can do this as ``admin`` via the Web UI or CLI. **Hint:** the
|
||||
``hbacsvc`` plugin provides this functionality.
|
||||
|
||||
Next, add an HBAC rule allowing members of the ``sysadmin`` user
|
||||
group access to ``app`` (on any host)::
|
||||
|
||||
[client]$ ipa hbacrule-add --hostcat=all sysadmin_app
|
||||
------------------------------
|
||||
Added HBAC rule "sysadmin_app"
|
||||
------------------------------
|
||||
Rule name: sysadmin_app
|
||||
Host category: all
|
||||
Enabled: TRUE
|
||||
|
||||
[client]$ ipa hbacrule-add-user sysadmin_app --group sysadmin
|
||||
Rule name: sysadmin_app
|
||||
Host category: all
|
||||
Enabled: TRUE
|
||||
User Groups: sysadmin
|
||||
-------------------------
|
||||
Number of members added 1
|
||||
-------------------------
|
||||
|
||||
[client]$ ipa hbacrule-add-service sysadmin_app --hbacsvcs app
|
||||
Rule name: sysadmin_app
|
||||
Host category: all
|
||||
Enabled: TRUE
|
||||
User Groups: sysadmin
|
||||
Services: app
|
||||
-------------------------
|
||||
Number of members added 1
|
||||
-------------------------
|
||||
|
||||
Next, define the PAM service on ``client``. The name must match the
|
||||
``hbacsvc`` name (in our case: ``app``), and the name is indicated
|
||||
by the *name of the file* that configures the PAM stack. Create
|
||||
``/etc/pam.d/app`` with the following contents::
|
||||
|
||||
account required pam_sss.so
|
||||
|
||||
Finally, update the Apache configuration. Find the line::
|
||||
|
||||
Require valid-user
|
||||
|
||||
Replace with::
|
||||
|
||||
Require pam-account app
|
||||
|
||||
Also add the ``LoadModule`` directive to the top of the file::
|
||||
|
||||
LoadModule authnz_pam_module modules/mod_authnz_pam.so
|
||||
|
||||
Once again, we must set a special SELinux boolean to allow
|
||||
``mod_authnz_pam`` to work::
|
||||
|
||||
[client]$ sudo setsebool -P allow_httpd_mod_auth_pam 1
|
||||
|
||||
Restart Apache and try and perform the same ``curl`` request again
|
||||
as ``alice``. Everything should work as before because ``alice`` is
|
||||
a member of the ``sysadmin`` group. What happens when you are
|
||||
authenticated as ``bob`` instead?
|
||||
|
||||
This unit is now concluded. Now that you have mastered web app
|
||||
authentication, you'll want to configure TLS for your site. Proceed
|
||||
to
|
||||
:ref:`Unit 6: Service certificates <6-cert-management>`.
|
||||
136
doc/workshop/6-cert-management.rst
Normal file
136
doc/workshop/6-cert-management.rst
Normal file
@@ -0,0 +1,136 @@
|
||||
.. _6-cert-management:
|
||||
|
||||
Unit 6: Service certificates
|
||||
================================
|
||||
|
||||
You probably noticed that the web service was not hosted over HTTPS,
|
||||
so there is no TLS-based authentication or confidentiality. In this
|
||||
unit, we will issue an X.509 certificate for the web service via
|
||||
the *Certmonger* program.
|
||||
|
||||
Certmonger supports multiple CAs including FreeIPA's CA, and can
|
||||
generate keys, issue certificate requests, track certificates, and
|
||||
renew tracked certificates when the expiration time approaches.
|
||||
Will also use ``mod_ssl`` with Apache.
|
||||
|
||||
Issue the service certificate
|
||||
-----------------------------
|
||||
|
||||
Let's start by confirming that the HTTP service does not yet have a
|
||||
certificate::
|
||||
|
||||
[client]$ ipa service-show HTTP/client.ipademo.local
|
||||
Principal name: HTTP/client.ipademo.local@IPADEMO.LOCAL
|
||||
Principal alias: HTTP/client.ipademo.local@IPADEMO.LOCAL
|
||||
Keytab: True
|
||||
Managed by: client.ipademo.local
|
||||
|
||||
Enable and start Certmonger::
|
||||
|
||||
[client]$ sudo systemctl enable --now certmonger
|
||||
Created symlink /etc/systemd/system/multi-user.target.wants/certmonger.service → /usr/lib/systemd/system/certmonger.service.
|
||||
|
||||
Now let's request a certificate. We will generate keys and store
|
||||
certificates in the NSS database at ``/etc/httpd/alias``::
|
||||
|
||||
[client]$ sudo ipa-getcert request \
|
||||
-f /etc/pki/tls/certs/app.crt \
|
||||
-k /etc/pki/tls/private/app.key \
|
||||
-K HTTP/client.ipademo.local \
|
||||
-D client.ipademo.local
|
||||
New signing request "20180603185400" added.
|
||||
|
||||
Let's break down some of those command arguments.
|
||||
|
||||
``-k <path>``
|
||||
Path to private key (Certmonger will generate it)
|
||||
``-f <path>``
|
||||
Path to certificate (where it will be saved after being issued)
|
||||
``-K <principal>``
|
||||
Kerberos service principal; because different kinds of services
|
||||
may be accessed at one hostname, this argument tells Certmonger
|
||||
which service principal is the subject
|
||||
``-D <dnsname>``
|
||||
Requests the given domain name to appear in the *Subject
|
||||
Alternative Name (SAN)* extension; today the *Common Name (CN)*
|
||||
field is no longer used by browsers so the SAN value is essential
|
||||
|
||||
Another important option is ``-N <subject-name>``. It defaults to
|
||||
the system hostname, which in our case (``client.ipademo.local``) is
|
||||
appropriate.
|
||||
|
||||
Let's check the status of our certificate request using the tracking
|
||||
identifier given in the ``ipa-getcert request`` output::
|
||||
|
||||
[client]$ sudo getcert list -i 20180603185400
|
||||
Number of certificates and requests being tracked: 1.
|
||||
Request ID '20180603185400':
|
||||
status: MONITORING
|
||||
stuck: no
|
||||
key pair storage: type=FILE,location='/etc/pki/tls/private/app.key'
|
||||
certificate: type=FILE,location='/etc/pki/tls/certs/app.crt'
|
||||
CA: IPA
|
||||
issuer: CN=Certificate Authority,O=IPADEMO.LOCAL
|
||||
subject: CN=client.ipademo.local,O=IPADEMO.LOCAL
|
||||
expires: 2020-06-03 18:54:00 UTC
|
||||
dns: client.ipademo.local
|
||||
principal name: HTTP/client.ipademo.local@IPADEMO.LOCAL
|
||||
key usage: digitalSignature,nonRepudiation,keyEncipherment,dataEncipherment
|
||||
eku: id-kp-serverAuth,id-kp-clientAuth
|
||||
pre-save command:
|
||||
post-save command:
|
||||
track: yes
|
||||
auto-renew: yes
|
||||
|
||||
|
||||
Confirm that the certificate was issued and that Certmonger is now
|
||||
``MONITORING`` the certificate and will ``auto-renew`` it when it is
|
||||
close to expiration. Now if you run ``ipa service-show``, you will
|
||||
see a number of attributes related to the certificate, including the
|
||||
certificate itself. Can you work out how to save the PEM-encoded
|
||||
certificate to a file?
|
||||
|
||||
Set up TLS for Apache
|
||||
---------------------
|
||||
|
||||
Now we can reconfigure Apache to serve our app over TLS. Update
|
||||
``app.conf`` to listen on port 443 and add the SSL directives::
|
||||
|
||||
...
|
||||
Listen 443
|
||||
|
||||
<VirtualHost *:443>
|
||||
SSLEngine on
|
||||
SSLCertificateFile "/etc/pki/tls/certs/app.crt"
|
||||
SSLCertificateKeyFile "/etc/pki/tls/private/app.key"
|
||||
|
||||
ServerName client.ipademo.local
|
||||
...
|
||||
|
||||
|
||||
Restart Apache and make a request to the app over HTTPS::
|
||||
|
||||
[client]$ sudo systemctl restart httpd
|
||||
[client]$ curl -u : --negotiate https://client.ipademo.local
|
||||
LOGGED IN AS: alice@IPADEMO.LOCAL
|
||||
|
||||
REMOTE_* REQUEST VARIABLES:
|
||||
|
||||
REMOTE_USER: alice@IPADEMO.LOCAL
|
||||
REMOTE_USER_GROUP_1: ipausers
|
||||
REMOTE_USER_GROUP_2: sysadmin
|
||||
REMOTE_USER_GROUP_N: 2
|
||||
REMOTE_USER_FIRSTNAME: Alice
|
||||
REMOTE_USER_LASTNAME: Alice
|
||||
REMOTE_USER_MAIL: alice@ipademo.local
|
||||
REMOTE_ADDR: 192.168.33.20
|
||||
REMOTE_PORT: 51876
|
||||
|
||||
|
||||
You can now proceed to
|
||||
:ref:`Unit 7: Replica installation <7-replica-install>`
|
||||
or
|
||||
:ref:`Unit 8: Sudo rule management <8-sudorule>`.
|
||||
Otherwise,
|
||||
:ref:`return to the curriculum overview <curriculum-overview>`
|
||||
to see all the options.
|
||||
64
doc/workshop/7-replica-install.rst
Normal file
64
doc/workshop/7-replica-install.rst
Normal file
@@ -0,0 +1,64 @@
|
||||
.. _7-replica-install:
|
||||
|
||||
Unit 7: Replica installation
|
||||
==============================
|
||||
|
||||
**Prerequisites**:
|
||||
|
||||
- :ref:`Unit 1: Installing the FreeIPA server <1-server-install>`
|
||||
|
||||
FreeIPA is designed to be run in a replicated multi-master
|
||||
environment. In this unit, we will install a replica of the
|
||||
existing master. For recommended production topologies, see
|
||||
https://www.freeipa.org/page/Deployment_Recommendations#Servers.2FReplicas.
|
||||
|
||||
If you have disabled the ``allow_all`` HBAC rule, add a new rule
|
||||
that will **allow ``admin`` to access the ``sshd`` service on any
|
||||
host**.
|
||||
|
||||
Client installation
|
||||
-------------------
|
||||
|
||||
The first step of replica creation is to enrol the machine that will
|
||||
become the replica. SSH to the ``replica`` VM and enrol it per
|
||||
:ref:`Unit 2: Enrolling client machines <2-client-install>`
|
||||
|
||||
Replica promotion
|
||||
-----------------
|
||||
|
||||
Now promote the client to server. We will set up the replica
|
||||
*without* the CA or DNS role. In a production deployment there
|
||||
should be at least one instance of these services in each data
|
||||
centre. These roles can be configured later via
|
||||
``ipa-ca-install(1)`` and ``ipa-dns-install(1)``.
|
||||
|
||||
::
|
||||
|
||||
[replica]$ sudo ipa-replica-install
|
||||
Password for admin@IPADEMO.LOCAL:
|
||||
ipaserver.install.server.replicainstall: ERROR Reverse DNS resolution of address 192.168.33.10 (server.ipademo.local) failed. Clients may not function properly. Please check your DNS setup. (Note that this check queries IPA DNS directly and ignores /etc/hosts.)
|
||||
Continue? [no]: yes
|
||||
Run connection check to master
|
||||
Connection check OK
|
||||
Configuring directory server (dirsrv). Estimated time: 30 seconds
|
||||
[1/41]: creating directory server instance
|
||||
[2/41]: enabling ldapi
|
||||
...
|
||||
|
||||
The rest of the replica installation process is almost identical to
|
||||
server installation. One important difference is the initial
|
||||
replication of data to the new Directory Server instance::
|
||||
|
||||
[28/41]: setting up initial replication
|
||||
Starting replication, please wait until this has completed.
|
||||
Update in progress, 4 seconds elapsed
|
||||
Update succeeded
|
||||
|
||||
After ``ipa-replica-install`` finishes, the replica is operational.
|
||||
LDAP changes on any server will be replicated to all other servers.
|
||||
|
||||
You can proceed to
|
||||
:ref:`Unit 8: Sudo rule management <8-sudorule>`
|
||||
or
|
||||
:ref:`return to the curriculum overview <curriculum-overview>`
|
||||
to see all the available topics.
|
||||
246
doc/workshop/8-sudorule.rst
Normal file
246
doc/workshop/8-sudorule.rst
Normal file
@@ -0,0 +1,246 @@
|
||||
.. _8-sudorule:
|
||||
|
||||
Unit 8: Sudo rule management
|
||||
============================
|
||||
|
||||
**Prerequisites**:
|
||||
|
||||
- :ref:`Unit 3: User management and Kerberos authentication <3-user-management>`
|
||||
- :ref:`Unit 4: Host-based access control (HBAC) <4-hbac>`
|
||||
|
||||
Sudo is a program that allows users to run programs as another user
|
||||
with different privileges (possibly ``root``). Sudo rules provide
|
||||
fine-grained control over who can execute which processes, as which
|
||||
users. FreeIPA allows centralised management of Sudo rules. To
|
||||
simplify management, Sudo rules can refer to User Groups, Host
|
||||
Groups and *Command Groups* as well as individual users, hosts and
|
||||
commands.
|
||||
|
||||
Older versions of sudo did not require pam access for passwordless
|
||||
rules (e.g. rules with the NOPASSWD keyword).
|
||||
sudo-1.8.23 and newer require pam access for all rules.
|
||||
|
||||
The goal of this unit is to allow ``alice`` (being a ``sysadmin``)
|
||||
to run any command on any FreeIPA-enrolled machine, and to allow
|
||||
``bob`` (who is merely a web server administrator) to control
|
||||
``httpd`` on hosts that are ``webservers``.
|
||||
|
||||
As of FreeIPA 4.6.90.pre2, you should enable SSSD's sudo responder by running::
|
||||
|
||||
[client]$ sudo authselect enable-feature with-sudo
|
||||
|
||||
Restart SSSD::
|
||||
|
||||
[client]$ sudo systemctl restart sssd
|
||||
|
||||
Permitting ``alice`` to run all commmands
|
||||
-----------------------------------------
|
||||
|
||||
Let's deal with ``alice`` first. Before we do anything else, log in
|
||||
as ``alice`` and attempt to run the ``id`` command as ``root``.
|
||||
Observe that the action is denied::
|
||||
|
||||
[client]$ su -l alice
|
||||
Password:
|
||||
|
||||
[alice@client]$ sudo id
|
||||
[sudo] password for alice:
|
||||
alice is not allowed to run sudo on client. This incident will be reported.
|
||||
|
||||
[alice@client]$ exit
|
||||
logout
|
||||
|
||||
Now define the ``sysadmin_sudo`` rule, which allows members of the
|
||||
``sysadmin`` User Group to to run any command on any host::
|
||||
|
||||
[client]$ ipa sudorule-add sysadmin_sudo \
|
||||
--hostcat=all --runasusercat=all --runasgroupcat=all --cmdcat=all
|
||||
-------------------------------
|
||||
Added Sudo Rule "sysadmin_sudo"
|
||||
-------------------------------
|
||||
Rule name: sysadmin_sudo
|
||||
Enabled: TRUE
|
||||
Host category: all
|
||||
Command category: all
|
||||
RunAs User category: all
|
||||
RunAs Group category: all
|
||||
|
||||
Next add the ``sysadmin`` User Group to the Sudo rule::
|
||||
|
||||
[client]$ ipa sudorule-add-user sysadmin_sudo --group sysadmin
|
||||
Rule name: sysadmin_sudo
|
||||
Enabled: TRUE
|
||||
Host category: all
|
||||
Command category: all
|
||||
RunAs User category: all
|
||||
RunAs Group category: all
|
||||
User Groups: sysadmin
|
||||
-------------------------
|
||||
Number of members added 1
|
||||
-------------------------
|
||||
|
||||
Now attempt to ``sudo id`` as ``alice`` again::
|
||||
|
||||
[client]$ su -l alice
|
||||
Password:
|
||||
|
||||
[alice@client]$ sudo id
|
||||
[sudo] password for alice:
|
||||
uid=0(root) gid=0(root) groups=0(root) context=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023
|
||||
|
||||
This time the action was allowed, and we can see from the output
|
||||
that ``alice`` indeed executed the ``id`` command as ``root``.
|
||||
|
||||
**Note:** if the command is prevented there may be some stale cache
|
||||
entries. Move on with the workshop and try again in 5 minutes.
|
||||
|
||||
|
||||
Permitting ``bob`` to run web administration commands
|
||||
-----------------------------------------------------
|
||||
|
||||
Now let us turn our attention to ``bob``. The goal is to allow
|
||||
``bob`` and other web servers administrators to run commands related
|
||||
to web server administration (and only such commands).
|
||||
|
||||
First, create a new User Group named ``webadmin`` and add ``bob`` as a
|
||||
member. Add an ``hbacrule`` that allows ``bob`` to log into hosts
|
||||
that are members of the ``webservers`` Host Group using the ``sshd``
|
||||
service.
|
||||
|
||||
Once this is done you should be able to login, but not use ``su -l``::
|
||||
|
||||
[client]$ su -l bob
|
||||
Password:
|
||||
|
||||
[bob@client]$ su -l bob
|
||||
Password:
|
||||
su: Permission denied
|
||||
|
||||
Then, let's observe that ``bob`` currently cannot restart Apache::
|
||||
|
||||
[bob@client]$ sudo systemctl restart httpd
|
||||
[sudo] password for bob:
|
||||
sudo: PAM account management error: Permission denied
|
||||
|
||||
Take note that the error is different from the one alice got, which was::
|
||||
|
||||
alice is not allowed to run sudo on client. This incident will be reported.
|
||||
|
||||
While the HBAC rule alice uses (sysadmin_webservers) was created with
|
||||
"--servicecat=all", the HBAC rule for bob was created with sshd in mind,
|
||||
like this::
|
||||
|
||||
[server]$ ipa hbacrule-add-service webadmin_webservers --hbacsvcs=sshd
|
||||
|
||||
As bob needs to run both ``su -l`` and ``sudo``, add both commands to
|
||||
the list of allowed services in your access control rule, for instance::
|
||||
|
||||
[server]$ ipa hbacrule-add-service webadmin_webservers \
|
||||
--hbacsvcs=sudo --hbacsvcs=su-l
|
||||
|
||||
Now login and logout as bob. Not only bob should now be able to use
|
||||
``su -l``, but the error message from ``sudo`` should change::
|
||||
|
||||
[bob@client]$ sudo systemctl restart httpd
|
||||
[sudo] password for bob:
|
||||
Sorry, user bob is not allowed to execute '/bin/systemctl restart httpd' as root on client.ipademo.local.
|
||||
|
||||
Now define the ``webadmin_sudo`` rule. Note that we *do not* use
|
||||
``--hostcat=all`` or ``cmdcat=all`` this time.
|
||||
|
||||
::
|
||||
|
||||
[client]$ ipa sudorule-add webadmin_sudo \
|
||||
--runasusercat=all --runasgroupcat=all
|
||||
-------------------------------
|
||||
Added Sudo Rule "webadmin_sudo"
|
||||
-------------------------------
|
||||
Rule name: webadmin_sudo
|
||||
Enabled: TRUE
|
||||
RunAs User category: all
|
||||
RunAs Group category: all
|
||||
|
||||
|
||||
Add the ``webadmin`` User Group and ``webservers`` Host Group to the rule::
|
||||
|
||||
[client]$ ipa sudorule-add-user webadmin_sudo --group webadmin
|
||||
Rule name: webadmin_sudo
|
||||
Enabled: TRUE
|
||||
RunAs User category: all
|
||||
RunAs Group category: all
|
||||
User Groups: webadmin
|
||||
-------------------------
|
||||
Number of members added 1
|
||||
-------------------------
|
||||
|
||||
[client]$ ipa sudorule-add-host webadmin_sudo --hostgroup webservers
|
||||
Rule name: webadmin_sudo
|
||||
Enabled: TRUE
|
||||
RunAs User category: all
|
||||
RunAs Group category: all
|
||||
User Groups: webadmin
|
||||
Host Groups: webservers
|
||||
-------------------------
|
||||
Number of members added 1
|
||||
-------------------------
|
||||
|
||||
Next, define *Sudo Commands* and a *Sudo Command Group* for
|
||||
web server administration::
|
||||
|
||||
[client]$ ipa sudocmd-add "/usr/bin/systemctl start httpd"
|
||||
---------------------------------------------------
|
||||
Added Sudo Command "/usr/bin/systemctl start httpd"
|
||||
---------------------------------------------------
|
||||
Sudo Command: /usr/bin/systemctl start httpd
|
||||
|
||||
[client]$ ipa sudocmd-add "/usr/bin/systemctl restart httpd"
|
||||
-----------------------------------------------------
|
||||
Added Sudo Command "/usr/bin/systemctl restart httpd"
|
||||
-----------------------------------------------------
|
||||
Sudo Command: /usr/bin/systemctl restart httpd
|
||||
|
||||
[client]$ ipa sudocmdgroup-add webadmin_cmds
|
||||
----------------------------------------
|
||||
Added Sudo Command Group "webadmin_cmds"
|
||||
----------------------------------------
|
||||
Sudo Command Group: webadmin_cmds
|
||||
|
||||
[client]$ ipa sudocmdgroup-add-member webadmin_cmds \
|
||||
--sudocmds "/usr/bin/systemctl start httpd" \
|
||||
--sudocmds "/usr/bin/systemctl restart httpd"
|
||||
Sudo Command Group: webadmin_cmds
|
||||
Member Sudo commands: /usr/bin/systemctl start httpd, /usr/bin/systemctl restart httpd
|
||||
-------------------------
|
||||
Number of members added 2
|
||||
-------------------------
|
||||
|
||||
Finally, add this new command group to the Sudo rule::
|
||||
|
||||
[client]$ ipa sudorule-add-allow-command webadmin_sudo \
|
||||
--sudocmdgroups webadmin_cmds
|
||||
Rule name: webadmin_sudo
|
||||
Enabled: TRUE
|
||||
RunAs User category: all
|
||||
RunAs Group category: all
|
||||
User Groups: webadmin
|
||||
Host Groups: webservers
|
||||
Sudo Allow Command Groups: webadmin_cmds
|
||||
-------------------------
|
||||
Number of members added 1
|
||||
-------------------------
|
||||
|
||||
Now log in again as ``bob`` and observe that we have reached our goal: he can
|
||||
restart (or start) Apache, but not run other commands via ``sudo``::
|
||||
|
||||
[client]$ su -l bob
|
||||
Password:
|
||||
|
||||
[bob@client]$ sudo systemctl restart httpd
|
||||
[sudo] password for bob:
|
||||
|
||||
[bob@client]$ sudo id
|
||||
Sorry, user bob is not allowed to execute '/bin/id' as root on client.ipademo.local.
|
||||
|
||||
|
||||
This concludes the unit. Now that you have Sudo rules working,
|
||||
proceed to :ref:`Unit 9: SELinux User Maps <9-selinux-user-map>`.
|
||||
143
doc/workshop/9-selinux-user-map.rst
Normal file
143
doc/workshop/9-selinux-user-map.rst
Normal file
@@ -0,0 +1,143 @@
|
||||
.. _9-selinux-user-map:
|
||||
|
||||
Unit 9: SELinux User Maps
|
||||
=========================
|
||||
|
||||
**Prerequisites**:
|
||||
|
||||
- :ref:`Unit 3: User management and Kerberos authentication <3-user-management>`
|
||||
- :ref:`Unit 4: Host-based access control (HBAC) <4-hbac>`
|
||||
- :ref:`Unit 8: Sudo rule management <8-sudorule>`
|
||||
|
||||
SELinux is a *mandatory access controls* mechanism for Linux,
|
||||
providing more powerful and flexible access control than traditional
|
||||
Unix permissions. Users have an SELinux *context* consisting of a
|
||||
*user*, *role* and *type*. In this unit, you will cause users
|
||||
to be *confined* by an SELinux *role-based access control (RBAC)*
|
||||
policy when the log into hosts that are members of the
|
||||
``webservers`` Host Group. You will also learn how to change a
|
||||
user's SELinux context when they execute commands via Sudo.
|
||||
|
||||
**Note:** SELinux contexts are applied during PAM-based login, so
|
||||
when testing our changes in this unit ``su -l <user>`` will not
|
||||
suffice: it is necessary to log in via SSH. You can do this from
|
||||
any of the VMs (even ``client`` itself).
|
||||
|
||||
Confining users
|
||||
---------------
|
||||
|
||||
Log in as ``alice`` and run ``id -Z`` to see her current SELinux
|
||||
context::
|
||||
|
||||
[alice@client]$ id -Z
|
||||
unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023
|
||||
|
||||
``alice`` is currently *unconfined*. We want her to be confined to
|
||||
the ``staff_u`` context when she logs in, to limit the impact of an
|
||||
account compromise.
|
||||
|
||||
SELinux User Maps can refer to users and hosts directly, or they can
|
||||
inherit the users and hosts of an existing HBAC rule. Because
|
||||
access control is defined by HBAC, it is a good administration
|
||||
practice to link SELinux User Maps to HBAC rules, so that when users
|
||||
or hosts are added to the HBAC rule, the correct SELinux context
|
||||
will automatically be used.
|
||||
|
||||
Recall that members of the ``sysadmin`` User Group already have
|
||||
access to ``webservers`` via the ``sysadmin_webservers`` rule that
|
||||
was created in :ref:`Unit 4: Host-based access control (HBAC)<4-hbac>`. Create
|
||||
the SELinux User Map::
|
||||
|
||||
[client]$ ipa selinuxusermap-add sysadmin_staff_t \
|
||||
--hbacrule sysadmin_webservers --selinuxuser staff_u:s0-s0:c0.c1023
|
||||
-----------------------------------------
|
||||
Added SELinux User Map "sysadmin_staff_t"
|
||||
-----------------------------------------
|
||||
Rule name: sysadmin_staff_t
|
||||
SELinux User: staff_u:s0-s0:c0.c1023
|
||||
HBAC Rule: sysadmin_webservers
|
||||
Enabled: TRUE
|
||||
|
||||
|
||||
Now login in as ``alice`` over SSH and observe that she is confined
|
||||
by the ``staff_u`` policy::
|
||||
|
||||
[server]$ ssh alice@client.ipademo.local
|
||||
alice@client.ipademo.local's password:
|
||||
Last login: Fri Sep 2 05:47:03 2016
|
||||
|
||||
[alice@client]$ id -Z
|
||||
staff_u:staff_r:staff_t:s0-s0:c0.c1023
|
||||
|
||||
|
||||
**Note:** in production use you should ensure that only one HBAC
|
||||
rule allows access for a given user/host/SELinux User Map
|
||||
combination. Only one SELinux policy will be applied, and if
|
||||
multiple policies match, the winning policy may be chosen
|
||||
inconsistently.
|
||||
|
||||
|
||||
Unconfined ``sudo``
|
||||
-------------------
|
||||
|
||||
``alice`` is now confined by the ``staff_u`` policy, but being a
|
||||
``sysadmin`` she needs to be unconfined when running commands via
|
||||
``sudo``. With the current configuration, commands run via ``sudo``
|
||||
inherit a user's context, as the following commands demonstrate::
|
||||
|
||||
[alice@client]$ sudo -s
|
||||
[sudo] password for alice:
|
||||
|
||||
sh-4.4# id
|
||||
uid=0(root) gid=0(root) groups=0(root) context=staff_u:staff_r:staff_t:s0-s0:c0.c1023
|
||||
|
||||
sh-4.4# echo "Hello, world!" > /etc/motd
|
||||
sh: /etc/motd: Permission denied
|
||||
|
||||
As you can see, ``alice`` became ``root``, but the SELinux
|
||||
confinement prevents her from writing ``/etc/motd`` (and many other
|
||||
things). Let's make it so that ``alice`` can do her job. We need
|
||||
to update the Sudo rule to change the SELinux context::
|
||||
|
||||
[alice@client]$ ipa sudorule-add-option sysadmin_sudo --sudooption type=unconfined_t
|
||||
-------------------------------------------------------------
|
||||
Added option "type=unconfined_t" to Sudo Rule "sysadmin_sudo"
|
||||
-------------------------------------------------------------
|
||||
Rule name: sysadmin_sudo
|
||||
Enabled: TRUE
|
||||
Host category: all
|
||||
Command category: all
|
||||
RunAs User category: all
|
||||
RunAs Group category: all
|
||||
Sudo Option: type=unconfined_t
|
||||
|
||||
[alice@client]$ ipa sudorule-add-option sysadmin_sudo --sudooption role=unconfined_r
|
||||
-------------------------------------------------------------
|
||||
Added option "role=unconfined_r" to Sudo Rule "sysadmin_sudo"
|
||||
-------------------------------------------------------------
|
||||
Rule name: sysadmin_sudo
|
||||
Enabled: TRUE
|
||||
Host category: all
|
||||
Command category: all
|
||||
RunAs User category: all
|
||||
RunAs Group category: all
|
||||
Sudo Option: type=unconfined_t, role=unconfined_r
|
||||
|
||||
Now when ``alice`` runs ``sudo`` it changes the SELinux context of
|
||||
the program being run::
|
||||
|
||||
[alice@client]$ sudo -s
|
||||
|
||||
sh-4.4# id -Z
|
||||
staff_u:unconfined_r:unconfined_t:s0-s0:c0.c1023
|
||||
|
||||
sh-4.4# echo "Hello, world!" > /etc/motd
|
||||
|
||||
sh-4.4# cat /etc/motd
|
||||
Hello, world!
|
||||
|
||||
This concludes the unit. You can now proceed to
|
||||
:ref:`Unit 10: SSH user and host key management <10-ssh-key-management>`
|
||||
or
|
||||
:ref:`return to the curriculum overview <curriculum-overview>`
|
||||
to see all the available topics.
|
||||
286
doc/workshop/README.rst
Normal file
286
doc/workshop/README.rst
Normal file
@@ -0,0 +1,286 @@
|
||||
.. _workshop:
|
||||
|
||||
Copyright 2015, 2016 Red Hat, Inc.
|
||||
|
||||
This work is licensed under the Creative Commons Attribution 4.0
|
||||
International License. To view a copy of this license, visit
|
||||
http://creativecommons.org/licenses/by/4.0/.
|
||||
|
||||
|
||||
Introduction
|
||||
============
|
||||
|
||||
FreeIPA_ is a centralised identity management system. In this
|
||||
workshop you will learn how to deploy FreeIPA servers and enrol
|
||||
client machines, define and manage user and service identities, set
|
||||
up access policies, configure network services to take advantage of
|
||||
FreeIPA's authentication and authorisation facilities and issue
|
||||
X.509 certificates for services.
|
||||
|
||||
.. _FreeIPA: http://www.freeipa.org/page/Main_Page
|
||||
|
||||
.. _curriculum-overview:
|
||||
|
||||
Curriculum overview
|
||||
-------------------
|
||||
|
||||
Mandatory:
|
||||
|
||||
- :ref:`Unit 1: Installing the FreeIPA server <1-server-install>`
|
||||
- :ref:`Unit 2: Enrolling client machines <2-client-install>`
|
||||
- :ref:`Unit 3: User management and Kerberos authentication <3-user-management>`
|
||||
- :ref:`Unit 4: Host-based access control (HBAC) <4-hbac>`
|
||||
|
||||
Optional units—choose the topics that are relevant to you:
|
||||
|
||||
- :ref:`Unit 5: Web application authentication and authorisation <5-web-app-authnz>`
|
||||
- :ref:`Unit 6: Service certificates <6-cert-management>`
|
||||
- :ref:`Unit 7: Replica installation <7-replica-install>`
|
||||
- :ref:`Unit 8: Sudo rule management <8-sudorule>`
|
||||
- :ref:`Unit 9: SELinux User Maps <9-selinux-user-map>`
|
||||
- :ref:`Unit 10: SSH user and host key management <10-ssh-key-management>`
|
||||
- :ref:`Unit 11: Kerberos ticket policy <11-kerberos-ticket-policy>`
|
||||
- :ref:`Unit 12: External IdP support <12-external-idp-support>`
|
||||
|
||||
Editing files on VMs
|
||||
--------------------
|
||||
|
||||
Parts of the workshop involve editing files on virtual
|
||||
machines. The ``vi`` and GNU ``nano`` editors are available on the
|
||||
VMs. If you are not familiar with ``vi`` or you are unsure of what to use, you
|
||||
should choose ``nano``.
|
||||
|
||||
|
||||
Example commands
|
||||
----------------
|
||||
|
||||
This guide contains many examples of commands. Some of the commands
|
||||
should be executed on your host, others on a particular guest VM.
|
||||
For clarity, commands are annotated with the host on which they are
|
||||
meant to be executed, as in these examples::
|
||||
|
||||
$ echo "Run it on virtualisation host (no annotation)"
|
||||
|
||||
[server]$ echo "Run it on FreeIPA server"
|
||||
|
||||
[client]$ echo "Run it on IPA-enrolled client"
|
||||
|
||||
...
|
||||
|
||||
|
||||
Preparation
|
||||
===========
|
||||
|
||||
Some preparation is needed prior to the workshop. The workshop is
|
||||
designed to be carried out in a Vagrant_ environment that configures
|
||||
three networked virtual machines (VMs) with all software needed for
|
||||
the workshop. **The goal of this preparation** is to ``vagrant up``
|
||||
the VMs. After this preparation is completed you are ready to begin
|
||||
the workshop.
|
||||
|
||||
.. _Vagrant: https://www.vagrantup.com/
|
||||
|
||||
|
||||
Requirements
|
||||
------------
|
||||
|
||||
For the FreeIPA workshop you will need to:
|
||||
|
||||
- Install **Vagrant** and **VirtualBox**. (On Fedora, you can use **libvirt**
|
||||
instead of VirtualBox).
|
||||
|
||||
- Use Git to clone the repository containing the ``Vagrantfile``
|
||||
|
||||
- Fetch the Vagrant *box* for the workshop
|
||||
|
||||
- Add entries for the guest VMs to your hosts file (so you can
|
||||
access them by their hostname)
|
||||
|
||||
Please set up these items **prior to the workshop**. More detailed
|
||||
instructions follow.
|
||||
|
||||
|
||||
Install Vagrant and VirtualBox
|
||||
------------------------------
|
||||
|
||||
Fedora
|
||||
^^^^^^
|
||||
|
||||
If you intend to use the ``libvirt`` provider (recommended), install
|
||||
``vagrant-libvirt`` and ``vagrant-libvirt-doc``::
|
||||
|
||||
$ sudo dnf install -y vagrant-libvirt vagrant-libvirt-doc
|
||||
|
||||
Also ensure you have the latest versions of ``selinux-policy`` and
|
||||
``selinux-policy-targeted``.
|
||||
|
||||
Allow your regular user ID to start and stop Vagrant boxes using ``libvirt``.
|
||||
Add your user to ``libvirt`` group so you don't need to enter your administrator
|
||||
password everytime::
|
||||
|
||||
$ sudo gpasswd -a ${USER} libvirt
|
||||
$ newgrp libvirt
|
||||
|
||||
Finally restart the services::
|
||||
|
||||
$ systemctl restart libvirtd
|
||||
|
||||
More information: https://docs.fedoraproject.org/en-US/quick-docs/getting-started-with-virtualization/
|
||||
|
||||
Otherwise, you will use VirtualBox and the ``virtualbox`` provider.
|
||||
VirtualBox needs to build kernel modules, and that means that you must
|
||||
first install kernel headers and Dynamic Kernel Module Support::
|
||||
|
||||
$ sudo dnf install -y vagrant kernel-devel dkms
|
||||
|
||||
Next, install VirtualBox from the official VirtualBox package repository.
|
||||
Before using the repo, check that its contents match what appears
|
||||
in the transcript below (to make sure it wasn't tampered with)::
|
||||
|
||||
$ sudo curl -o /etc/yum.repos.d/virtualbox.repo \
|
||||
http://download.virtualbox.org/virtualbox/rpm/fedora/virtualbox.repo
|
||||
|
||||
$ cat /etc/yum.repos.d/virtualbox.repo
|
||||
[virtualbox]
|
||||
name=Fedora $releasever - $basearch - VirtualBox
|
||||
baseurl=http://download.virtualbox.org/virtualbox/rpm/fedora/$releasever/$basearch
|
||||
enabled=1
|
||||
gpgcheck=1
|
||||
repo_gpgcheck=1
|
||||
gpgkey=https://www.virtualbox.org/download/oracle_vbox.asc
|
||||
|
||||
$ sudo dnf install -y VirtualBox-6.1
|
||||
|
||||
Finally, load the kernel modules (you may need to restart your system for this to work)::
|
||||
|
||||
$ sudo modprobe vboxdrv vboxnetadp
|
||||
|
||||
|
||||
Mac OS X
|
||||
^^^^^^^^
|
||||
|
||||
Install Vagrant for Mac OS X from
|
||||
https://www.vagrantup.com/downloads.html.
|
||||
|
||||
Install VirtualBox 6.1 for **OS X hosts** from
|
||||
https://www.virtualbox.org/wiki/Downloads.
|
||||
|
||||
Install Git from https://git-scm.com/download/mac or via your
|
||||
preferred package manager.
|
||||
|
||||
|
||||
Debian / Ubuntu
|
||||
^^^^^^^^^^^^^^^
|
||||
|
||||
Install Vagrant, Git and VirtualBox::
|
||||
|
||||
$ sudo apt-get install -y vagrant git
|
||||
$ sudo apt-get install -y virtualbox-6.1
|
||||
|
||||
If VirtualBox 6.1 was not available in the official packages for
|
||||
your release, follow the instructions at
|
||||
https://www.virtualbox.org/wiki/Linux_Downloads to install it.
|
||||
|
||||
|
||||
Windows
|
||||
^^^^^^^
|
||||
|
||||
Install Vagrant via the ``.msi`` available from
|
||||
https://www.vagrantup.com/downloads.html.
|
||||
|
||||
Install VirtualBox for **Windows hosts** from
|
||||
https://www.virtualbox.org/wiki/Downloads.
|
||||
|
||||
You will also need to install an SSH client, and Git. Git for
|
||||
Windows also comes with an SSH client so just install Git from
|
||||
https://git-scm.com/download/win.
|
||||
|
||||
|
||||
Clone this repository
|
||||
---------------------
|
||||
|
||||
This repository contains the ``Vagrantfile`` that is used for the
|
||||
workshop, which you will need locally.
|
||||
|
||||
::
|
||||
|
||||
$ git clone https://github.com/freeipa/freeipa.git
|
||||
$ cd freeipa/doc/workshop
|
||||
|
||||
|
||||
Fetch Vagrant box
|
||||
-----------------
|
||||
|
||||
Please fetch the Vagrant box prior to the workshop. It is > 700MB
|
||||
so it may not be feasible to download it during the workshop.
|
||||
|
||||
::
|
||||
|
||||
$ vagrant box add freeipa/freeipa-workshop
|
||||
|
||||
|
||||
Add hosts file entries
|
||||
----------------------
|
||||
|
||||
*This step is optional. All units can be completed using the CLI
|
||||
only. But if you want to access the FreeIPA Web UI or other web
|
||||
servers on the VMs from your browser, follow these instructions.*
|
||||
|
||||
Add the following entries to your hosts file::
|
||||
|
||||
192.168.33.10 server.ipademo.local
|
||||
192.168.33.11 replica.ipademo.local
|
||||
192.168.33.20 client.ipademo.local
|
||||
|
||||
On Unix systems (including Mac OS X), the hosts file is ``/etc/hosts``
|
||||
(you need elevated permissions to edit it.)
|
||||
|
||||
On Windows, edit ``C:\Windows\System32\system\drivers\etc\hosts`` as
|
||||
*Administrator*.
|
||||
|
||||
|
||||
Next step
|
||||
---------
|
||||
|
||||
You are ready to begin the workshop. Continue to
|
||||
:ref:`Unit 1: Installing the FreeIPA server <1-server-install>`.
|
||||
|
||||
|
||||
After the workshop
|
||||
------------------
|
||||
|
||||
Here are some contact details and resources that may help you after
|
||||
the workshop is over:
|
||||
|
||||
- IRC: ``#freeipa`` and ``#sssd`` (Libera.chat)
|
||||
|
||||
- ``freeipa-users@lists.fedorahosted.org`` `mailing list
|
||||
<https://lists.fedoraproject.org/archives/list/freeipa-users@lists.fedorahosted.org/>`_
|
||||
|
||||
- `How To guides <https://www.freeipa.org/page/HowTos>`_: large
|
||||
index of articles about specialised tasks and integrations
|
||||
|
||||
- `Troubleshooting guide
|
||||
<https://www.freeipa.org/page/Troubleshooting>`_: how to debug
|
||||
common problems; how to report bugs
|
||||
|
||||
- `Bug tracker <https://pagure.io/freeipa>`_
|
||||
|
||||
- Information about the `FreeIPA public demo
|
||||
<https://www.freeipa.org/page/Demo>`_ instance
|
||||
|
||||
- `Deployment Recommendations
|
||||
<https://www.freeipa.org/page/Deployment_Recommendations>`_:
|
||||
things to consider when going into production
|
||||
|
||||
- `Documentation index
|
||||
<https://www.freeipa.org/page/Documentation>`_
|
||||
|
||||
- `FreeIPA Planet <http://planet.freeipa.org/>`_: aggregate of
|
||||
several FreeIPA and identity-management related blogs
|
||||
|
||||
- `GitHub organisation <https://github.com/freeipa>`_. In addition
|
||||
to the `main repository <https://github.com/freeipa/freeipa>`_
|
||||
there are various tools, CI-related projects and documentation.
|
||||
|
||||
- `Development roadmap <https://www.freeipa.org/page/Roadmap>`_
|
||||
82
doc/workshop/Vagrantfile
vendored
Normal file
82
doc/workshop/Vagrantfile
vendored
Normal file
@@ -0,0 +1,82 @@
|
||||
# -*- mode: ruby -*-
|
||||
# vi: set ft=ruby :
|
||||
|
||||
Vagrant.configure(2) do |config|
|
||||
|
||||
# Replace this with "fedora/34-cloud-base" (or latest) for a fresh box without
|
||||
# pre-installed freeipa packages, you must also uncomment shell provisioning step
|
||||
# at the bottom of this file.
|
||||
# config.vm.box = "fedora/34-cloud-base"
|
||||
config.vm.box = "freeipa/freeipa-workshop"
|
||||
|
||||
config.vm.synced_folder ".", "/vagrant", disabled: true
|
||||
|
||||
config.vm.provider :libvirt do |libvirt|
|
||||
libvirt.qemu_use_session = false
|
||||
libvirt.memory = 1024
|
||||
end
|
||||
|
||||
config.vm.provider :virtualbox do |virtualbox|
|
||||
virtualbox.memory = 1536
|
||||
end
|
||||
|
||||
config.vm.define "server" do |server|
|
||||
server.vm.network "private_network", ip: "192.168.33.10"
|
||||
server.vm.hostname = "server.ipademo.local"
|
||||
|
||||
config.vm.provider "virtualbox" do |v|
|
||||
v.memory = 1536
|
||||
end
|
||||
config.vm.provider "libvirt" do |v|
|
||||
v.memory = 1536
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
config.vm.define "replica" do |replica|
|
||||
replica.vm.network "private_network", ip: "192.168.33.11"
|
||||
replica.vm.hostname = "replica.ipademo.local"
|
||||
|
||||
replica.vm.provision "shell",
|
||||
inline: 'echo "PEERDNS=no" >> /etc/sysconfig/network-scripts/ifcfg-eth0'
|
||||
replica.vm.provision "shell",
|
||||
inline: 'echo "DNS1=192.168.33.10" >> /etc/sysconfig/network-scripts/ifcfg-eth1'
|
||||
replica.vm.provision "shell",
|
||||
inline: 'printf "DNS=192.168.33.10\nDomains=~." >> /etc/systemd/resolved.conf'
|
||||
replica.vm.provision "shell",
|
||||
inline: 'systemctl restart systemd-resolved'
|
||||
|
||||
config.vm.provider "virtualbox" do |v|
|
||||
v.memory = 1536
|
||||
end
|
||||
config.vm.provider "libvirt" do |v|
|
||||
v.memory = 1536
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
config.vm.define "client" do |client|
|
||||
client.vm.network "private_network", ip: "192.168.33.20"
|
||||
client.vm.hostname = "client.ipademo.local"
|
||||
|
||||
client.vm.provision "shell",
|
||||
inline: 'echo "PEERDNS=no" >> /etc/sysconfig/network-scripts/ifcfg-eth0'
|
||||
client.vm.provision "shell",
|
||||
inline: 'echo "DNS1=192.168.33.10" >> /etc/sysconfig/network-scripts/ifcfg-eth1'
|
||||
client.vm.provision "shell",
|
||||
inline: 'printf "DNS=192.168.33.10\nDomains=~." >> /etc/systemd/resolved.conf'
|
||||
client.vm.provision "shell",
|
||||
inline: 'systemctl restart systemd-resolved'
|
||||
client.vm.provision "shell",
|
||||
inline: 'sudo sed -i "s/^/#/g" /etc/httpd/conf.d/ssl.conf'
|
||||
client.vm.provision "shell",
|
||||
inline: 'systemctl -q enable httpd && systemctl start httpd'
|
||||
client.vm.provision "shell",
|
||||
inline: 'systemctl -q enable oddjobd && systemctl start oddjobd'
|
||||
end
|
||||
|
||||
# Uncomment line below when using Fedora's cloud base box.
|
||||
# config.vm.provision "shell", path: "workshop-install-packages.sh"
|
||||
config.vm.provision "shell", path: "workshop-ipa-customizations.sh"
|
||||
|
||||
end
|
||||
71
doc/workshop/building.rst
Normal file
71
doc/workshop/building.rst
Normal file
@@ -0,0 +1,71 @@
|
||||
.. _building:
|
||||
|
||||
Building Vagrant box images
|
||||
===========================
|
||||
|
||||
This document describes how to build vagrant box images for the
|
||||
FreeIPA workshop.
|
||||
|
||||
Requirements
|
||||
------------
|
||||
|
||||
- Install packer (http://packer.io/)
|
||||
- Install Vagrant, libvirt and VirtualBox
|
||||
- Clone the Fedora kickstarts repo (https://pagure.io/fedora-kickstarts)
|
||||
|
||||
|
||||
Packer template
|
||||
---------------
|
||||
|
||||
Packer template ``packer-template-fedora.json`` requires Fedora 34 kickstart file
|
||||
used by Fedora to build vagrant images:
|
||||
|
||||
- Clone the repo and checkout latest Fedora release branch::
|
||||
|
||||
$ git clone https://pagure.io/fedora-kickstarts.git
|
||||
$ cd fedora-kickstarts
|
||||
$ git checkout f34
|
||||
|
||||
- Install ``pykickstart`` package which provides ``ksflatten`` tool::
|
||||
|
||||
$ sudo dnf install pykickstart
|
||||
|
||||
- Generate the ``anaconda-ks.cfg`` file needed by flattening vagrant kickstart files
|
||||
and putting it onto the same folder as the packer template file::
|
||||
|
||||
$ ksflatten -c $FEDORA_KICKSTARTS_REPO/fedora-cloud-base-vagrant.ks > $FREEIPA_REPO/doc/workshop/anaconda-ks.cfg
|
||||
|
||||
|
||||
Building the vagrant images
|
||||
-----------------------------
|
||||
|
||||
Build the images::
|
||||
|
||||
$ cd $FREEIPA_REPO/doc/workshop
|
||||
$ BIN_PACKER build packer-template-fedora.json
|
||||
|
||||
|
||||
Uploading boxes to Vagrant Cloud
|
||||
----------------------------------
|
||||
|
||||
Vagrant by default looks for boxes in a directory called *Vagrant Cloud*.
|
||||
Therefore is is good to make images available there, so that people
|
||||
can easily download them as part of workshop preparation.
|
||||
|
||||
1. Log into https://app.vagrantup.com/.
|
||||
|
||||
2. Create or edit the *freeipa-workshop* box.
|
||||
|
||||
3. Create a new *version* of the box (left-hand menu). Each version
|
||||
can include images for multiple *providers*.
|
||||
|
||||
4. *Create new provider* for ***virtualbox*** and upload the
|
||||
corresponding ``.box`` file.
|
||||
|
||||
5. *Create new provider* for ***libvirt*** and upload the
|
||||
corresponding ``.box`` file. *libvirt* may not appear as an
|
||||
autocomplete option but type it in anyway.
|
||||
|
||||
6. *Release* the new version (this makes it available for
|
||||
Vagrant to download). *Edit* the version, then click *Release
|
||||
version*.
|
||||
35
doc/workshop/facilitators.rst
Normal file
35
doc/workshop/facilitators.rst
Normal file
@@ -0,0 +1,35 @@
|
||||
Notes for workshop facilitators
|
||||
===============================
|
||||
|
||||
Orientation presentation
|
||||
------------------------
|
||||
|
||||
It is suggested to begin the workshop with a short "orientation"
|
||||
presentation, which should cover:
|
||||
|
||||
- Goals of the workshop
|
||||
- Curriculum overview
|
||||
- High-level IdM concepts
|
||||
- High-level FreeIPA architecture
|
||||
- Further resources (this can be covered at end of workshop)
|
||||
|
||||
Here is an example presentation you are welcome to use:
|
||||
https://github.com/frasertweedale/talks/raw/master/2016-02-03-lca-freeipa-workshop/presentation.odp
|
||||
|
||||
Feedback
|
||||
--------
|
||||
|
||||
Please offer participants the opportunity to provide feedback about
|
||||
their workshop. It should include questions about their technical
|
||||
background and prior general IdM knowledge, as well as whether the
|
||||
workshop helped them learn FreeIPA, how difficult it was, etc.
|
||||
|
||||
Example: https://goo.gl/forms/UOkcsVROqV
|
||||
|
||||
|
||||
Vagrant boxes
|
||||
-------------
|
||||
|
||||
See :ref:`building` for instructions on building Vagrant boxes.
|
||||
At time of writing, the ``freeipa/freeipa-workshop`` box is
|
||||
FreeIPA 4.9.3 / Fedora 34, for the VirtualBox and libvirt providers.
|
||||
77
doc/workshop/packer-template-fedora.json
Normal file
77
doc/workshop/packer-template-fedora.json
Normal file
@@ -0,0 +1,77 @@
|
||||
{
|
||||
"builders": [{
|
||||
"type": "qemu",
|
||||
"iso_url": "{{user `iso_url`}}",
|
||||
"iso_checksum": "{{user `iso_checksum`}}",
|
||||
"output_directory": "output-{{user `box_name`}}-x86_64-{{build_type}}",
|
||||
"vm_name": "packer-{{user `box_name`}}-x86_64",
|
||||
"disk_size": "{{user `disk_size`}}",
|
||||
"headless": "{{user `headless`}}",
|
||||
"http_directory": ".",
|
||||
"boot_wait": "5s",
|
||||
"boot_command": [
|
||||
"<tab> ",
|
||||
"inst.ks=http://{{.HTTPIP}}:{{.HTTPPort}}/anaconda-ks.cfg ",
|
||||
"biosdevname=0 ",
|
||||
"net.ifnames=0 ",
|
||||
"<enter>"
|
||||
],
|
||||
"ssh_timeout": "{{user `ssh_timeout`}}",
|
||||
"ssh_username": "vagrant",
|
||||
"ssh_password": "vagrant",
|
||||
"shutdown_command": "sudo systemctl poweroff",
|
||||
"qemuargs": [
|
||||
["-m", "{{user `memory`}}"],
|
||||
["-smp", "{{user `cpus`}}"]
|
||||
]
|
||||
}, {
|
||||
"type": "virtualbox-iso",
|
||||
"guest_os_type": "Fedora_64",
|
||||
"iso_url": "{{user `iso_url`}}",
|
||||
"iso_checksum": "{{user `iso_checksum`}}",
|
||||
"output_directory": "output-{{user `box_name`}}-x86_64-{{build_type}}",
|
||||
"vm_name": "packer-{{user `box_name`}}-x86_64",
|
||||
"disk_size": "{{user `disk_size`}}",
|
||||
"headless": "{{user `headless`}}",
|
||||
"http_directory": ".",
|
||||
"boot_wait": "5s",
|
||||
"boot_command": [
|
||||
"<tab> ",
|
||||
"inst.ks=http://{{.HTTPIP}}:{{.HTTPPort}}/anaconda-ks.cfg ",
|
||||
"biosdevname=0 ",
|
||||
"net.ifnames=0 ",
|
||||
"<enter>"
|
||||
],
|
||||
"ssh_timeout": "{{user `ssh_timeout`}}",
|
||||
"ssh_username": "vagrant",
|
||||
"ssh_password": "vagrant",
|
||||
"shutdown_command": "sudo systemctl poweroff",
|
||||
"vboxmanage": [
|
||||
["modifyvm", "{{.Name}}", "--memory", "{{user `memory`}}"],
|
||||
["modifyvm", "{{.Name}}", "--cpus", "{{user `cpus`}}"]
|
||||
]
|
||||
}],
|
||||
"provisioners": [{
|
||||
"type": "shell",
|
||||
"scripts": [
|
||||
"workshop-install-packages.sh"
|
||||
]
|
||||
}],
|
||||
"post-processors": [{
|
||||
"type": "vagrant",
|
||||
"compression_level": "{{user `compression_level`}}",
|
||||
"output": "{{user `box_name`}}-x86_64-{{.Provider}}.box"
|
||||
}],
|
||||
"variables": {
|
||||
"box_name": "fedora-34",
|
||||
"iso_url": "{{user `mirror`}}/releases/34/Server/x86_64/iso/Fedora-Server-netinst-x86_64-34-1.2.iso",
|
||||
"iso_checksum": "file:{{user `mirror`}}/releases/34/Server/x86_64/iso/Fedora-Server-34-1.2-x86_64-CHECKSUM",
|
||||
"compression_level": "9",
|
||||
"cpus": "1",
|
||||
"disk_size": "40000",
|
||||
"headless": "false",
|
||||
"memory": "1024",
|
||||
"mirror": "http://download.fedoraproject.org/pub/fedora/linux",
|
||||
"ssh_timeout": "60m"
|
||||
}
|
||||
}
|
||||
57
doc/workshop/troubleshooting.rst
Normal file
57
doc/workshop/troubleshooting.rst
Normal file
@@ -0,0 +1,57 @@
|
||||
Troubleshooting
|
||||
===============
|
||||
|
||||
Local webserver
|
||||
---------------
|
||||
|
||||
Drop firewall::
|
||||
|
||||
sudo firewall-cmd --add-service=http
|
||||
|
||||
|
||||
DNS / hosts file issues
|
||||
-----------------------
|
||||
|
||||
Flush cache
|
||||
^^^^^^^^^^^
|
||||
|
||||
Note: some resolvers cache NX.
|
||||
|
||||
Max OS X::
|
||||
|
||||
dscacheutil -flushcache
|
||||
|
||||
Windows::
|
||||
|
||||
ipconfig /flush -- or is it /flushdns ?
|
||||
|
||||
|
||||
Virtual network
|
||||
---------------
|
||||
|
||||
If ``Vagrant::Errors::NetworkCollision`` occurs, try deleting host
|
||||
network device, e.g.::
|
||||
|
||||
sudo ifconfig virbr2 down
|
||||
|
||||
|
||||
*vagrant-libvirt* might have problems if the ``default`` network is
|
||||
up::
|
||||
|
||||
sudo virsh net-destroy default
|
||||
|
||||
|
||||
Vagrant
|
||||
-------
|
||||
|
||||
If ``vagrant up`` fails to SSH into VM, delete
|
||||
``~/.vagrant.d/insecure_private_key``. See
|
||||
https://stackoverflow.com/questions/28284112/.
|
||||
|
||||
|
||||
mod_lookup_identity
|
||||
-------------------
|
||||
|
||||
To flush cache::
|
||||
|
||||
$ sudo sss_cache -E
|
||||
3
doc/workshop/workshop-install-packages.sh
Normal file
3
doc/workshop/workshop-install-packages.sh
Normal file
@@ -0,0 +1,3 @@
|
||||
#!/bin/bash
|
||||
sudo dnf install -y freeipa-server freeipa-server-dns sssd-dbus mod_lookup_identity mod_authnz_pam haveged nmap-ncat nano pamtester bash-completion
|
||||
sudo dnf clean all
|
||||
47
doc/workshop/workshop-ipa-customizations.sh
Executable file
47
doc/workshop/workshop-ipa-customizations.sh
Executable file
@@ -0,0 +1,47 @@
|
||||
#!/bin/bash
|
||||
sudo systemctl enable haveged
|
||||
sudo sh -c "echo 'PS1=\"[\u@\h]\\\\$ \"' >> /etc/profile"
|
||||
sudo sh -c "echo 'PS1=\"[\h]\\\\$ \"' >> /etc/bashrc"
|
||||
sudo sh -c "echo '192.168.33.10 server.ipademo.local' >> /etc/hosts"
|
||||
sudo sh -c "echo '192.168.33.11 replica.ipademo.local' >> /etc/hosts"
|
||||
sudo sh -c "echo '192.168.33.20 client.ipademo.local' >> /etc/hosts"
|
||||
sudo rm -f /etc/httpd/conf.d/welcome.conf
|
||||
|
||||
sudo sh -c "cat >/usr/share/httpd/app.py" <<EOF
|
||||
def application(environ, start_response):
|
||||
start_response('200 OK', [('Content-Type', 'text/plain')])
|
||||
remote_user = environ.get('REMOTE_USER')
|
||||
|
||||
if remote_user is not None:
|
||||
yield "LOGGED IN AS: {}\n".format(remote_user).encode('utf8')
|
||||
else:
|
||||
yield b"NOT LOGGED IN\n"
|
||||
|
||||
yield b"\nREMOTE_* REQUEST VARIABLES:\n\n"
|
||||
|
||||
for k, v in environ.items():
|
||||
if k.startswith('REMOTE_'):
|
||||
yield " {}: {}\n".format(k, v).encode('utf8')
|
||||
EOF
|
||||
|
||||
sudo sh -c "cat >/etc/httpd/conf.d/app.conf" <<EOF
|
||||
<VirtualHost *:80>
|
||||
ServerName client.ipademo.local
|
||||
WSGIScriptAlias / /usr/share/httpd/app.py
|
||||
|
||||
<Directory /usr/share/httpd>
|
||||
<Files "app.py">
|
||||
Require all granted
|
||||
</Files>
|
||||
</Directory>
|
||||
</VirtualHost>
|
||||
EOF
|
||||
|
||||
# Vagrant's "change host name" sets the short host name. Before
|
||||
# we repair /etc/hosts (see below) let's reset /etc/hostname to
|
||||
# the *full* host name
|
||||
hostname --fqdn > /etc/hostname && hostname -F /etc/hostname
|
||||
|
||||
# Vagrant's "change host name" capability for Fedora maps hostname
|
||||
# to loopback. We must repair /etc/hosts
|
||||
sed -ri 's/127\.0\.0\.1\s.*/127.0.0.1 localhost localhost.localdomain/' /etc/hosts
|
||||
286
doc/workshop/workshop.rst
Normal file
286
doc/workshop/workshop.rst
Normal file
@@ -0,0 +1,286 @@
|
||||
.. _workshop:
|
||||
|
||||
Copyright 2015, 2016 Red Hat, Inc.
|
||||
|
||||
This work is licensed under the Creative Commons Attribution 4.0
|
||||
International License. To view a copy of this license, visit
|
||||
http://creativecommons.org/licenses/by/4.0/.
|
||||
|
||||
|
||||
Introduction
|
||||
============
|
||||
|
||||
FreeIPA_ is a centralised identity management system. In this
|
||||
workshop you will learn how to deploy FreeIPA servers and enrol
|
||||
client machines, define and manage user and service identities, set
|
||||
up access policies, configure network services to take advantage of
|
||||
FreeIPA's authentication and authorisation facilities and issue
|
||||
X.509 certificates for services.
|
||||
|
||||
.. _FreeIPA: http://www.freeipa.org/page/Main_Page
|
||||
|
||||
.. _curriculum-overview:
|
||||
|
||||
Curriculum overview
|
||||
-------------------
|
||||
|
||||
Mandatory:
|
||||
|
||||
- :ref:`Unit 1: Installing the FreeIPA server <1-server-install>`
|
||||
- :ref:`Unit 2: Enrolling client machines <2-client-install>`
|
||||
- :ref:`Unit 3: User management and Kerberos authentication <3-user-management>`
|
||||
- :ref:`Unit 4: Host-based access control (HBAC) <4-hbac>`
|
||||
|
||||
Optional units—choose the topics that are relevant to you:
|
||||
|
||||
- :ref:`Unit 5: Web application authentication and authorisation <5-web-app-authnz>`
|
||||
- :ref:`Unit 6: Service certificates <6-cert-management>`
|
||||
- :ref:`Unit 7: Replica installation <7-replica-install>`
|
||||
- :ref:`Unit 8: Sudo rule management <8-sudorule>`
|
||||
- :ref:`Unit 9: SELinux User Maps <9-selinux-user-map>`
|
||||
- :ref:`Unit 10: SSH user and host key management <10-ssh-key-management>`
|
||||
- :ref:`Unit 11: Kerberos ticket policy <11-kerberos-ticket-policy>`
|
||||
- :ref:`Unit 12: External IdP support <12-external-idp-support>`
|
||||
|
||||
Editing files on VMs
|
||||
--------------------
|
||||
|
||||
Parts of the workshop involve editing files on virtual
|
||||
machines. The ``vi`` and GNU ``nano`` editors are available on the
|
||||
VMs. If you are not familiar with ``vi`` or you are unsure of what to use, you
|
||||
should choose ``nano``.
|
||||
|
||||
|
||||
Example commands
|
||||
----------------
|
||||
|
||||
This guide contains many examples of commands. Some of the commands
|
||||
should be executed on your host, others on a particular guest VM.
|
||||
For clarity, commands are annotated with the host on which they are
|
||||
meant to be executed, as in these examples::
|
||||
|
||||
$ echo "Run it on virtualisation host (no annotation)"
|
||||
|
||||
[server]$ echo "Run it on FreeIPA server"
|
||||
|
||||
[client]$ echo "Run it on IPA-enrolled client"
|
||||
|
||||
...
|
||||
|
||||
|
||||
Preparation
|
||||
===========
|
||||
|
||||
Some preparation is needed prior to the workshop. The workshop is
|
||||
designed to be carried out in a Vagrant_ environment that configures
|
||||
three networked virtual machines (VMs) with all software needed for
|
||||
the workshop. **The goal of this preparation** is to ``vagrant up``
|
||||
the VMs. After this preparation is completed you are ready to begin
|
||||
the workshop.
|
||||
|
||||
.. _Vagrant: https://www.vagrantup.com/
|
||||
|
||||
|
||||
Requirements
|
||||
------------
|
||||
|
||||
For the FreeIPA workshop you will need to:
|
||||
|
||||
- Install **Vagrant** and **VirtualBox**. (On Fedora, you can use **libvirt**
|
||||
instead of VirtualBox).
|
||||
|
||||
- Use Git to clone the repository containing the ``Vagrantfile``
|
||||
|
||||
- Fetch the Vagrant *box* for the workshop
|
||||
|
||||
- Add entries for the guest VMs to your hosts file (so you can
|
||||
access them by their hostname)
|
||||
|
||||
Please set up these items **prior to the workshop**. More detailed
|
||||
instructions follow.
|
||||
|
||||
|
||||
Install Vagrant and VirtualBox
|
||||
------------------------------
|
||||
|
||||
Fedora
|
||||
^^^^^^
|
||||
|
||||
If you intend to use the ``libvirt`` provider (recommended), install
|
||||
``vagrant-libvirt`` and ``vagrant-libvirt-doc``::
|
||||
|
||||
$ sudo dnf install -y vagrant-libvirt vagrant-libvirt-doc
|
||||
|
||||
Also ensure you have the latest versions of ``selinux-policy`` and
|
||||
``selinux-policy-targeted``.
|
||||
|
||||
Allow your regular user ID to start and stop Vagrant boxes using ``libvirt``.
|
||||
Add your user to ``libvirt`` group so you don't need to enter your administrator
|
||||
password everytime::
|
||||
|
||||
$ sudo gpasswd -a ${USER} libvirt
|
||||
$ newgrp libvirt
|
||||
|
||||
Finally restart the services::
|
||||
|
||||
$ systemctl restart libvirtd
|
||||
|
||||
More information: https://docs.fedoraproject.org/en-US/quick-docs/getting-started-with-virtualization/
|
||||
|
||||
Otherwise, you will use VirtualBox and the ``virtualbox`` provider.
|
||||
VirtualBox needs to build kernel modules, and that means that you must
|
||||
first install kernel headers and Dynamic Kernel Module Support::
|
||||
|
||||
$ sudo dnf install -y vagrant kernel-devel dkms
|
||||
|
||||
Next, install VirtualBox from the official VirtualBox package repository.
|
||||
Before using the repo, check that its contents match what appears
|
||||
in the transcript below (to make sure it wasn't tampered with)::
|
||||
|
||||
$ sudo curl -o /etc/yum.repos.d/virtualbox.repo \
|
||||
http://download.virtualbox.org/virtualbox/rpm/fedora/virtualbox.repo
|
||||
|
||||
$ cat /etc/yum.repos.d/virtualbox.repo
|
||||
[virtualbox]
|
||||
name=Fedora $releasever - $basearch - VirtualBox
|
||||
baseurl=http://download.virtualbox.org/virtualbox/rpm/fedora/$releasever/$basearch
|
||||
enabled=1
|
||||
gpgcheck=1
|
||||
repo_gpgcheck=1
|
||||
gpgkey=https://www.virtualbox.org/download/oracle_vbox.asc
|
||||
|
||||
$ sudo dnf install -y VirtualBox-6.1
|
||||
|
||||
Finally, load the kernel modules (you may need to restart your system for this to work)::
|
||||
|
||||
$ sudo modprobe vboxdrv vboxnetadp
|
||||
|
||||
|
||||
Mac OS X
|
||||
^^^^^^^^
|
||||
|
||||
Install Vagrant for Mac OS X from
|
||||
https://www.vagrantup.com/downloads.html.
|
||||
|
||||
Install VirtualBox 6.1 for **OS X hosts** from
|
||||
https://www.virtualbox.org/wiki/Downloads.
|
||||
|
||||
Install Git from https://git-scm.com/download/mac or via your
|
||||
preferred package manager.
|
||||
|
||||
|
||||
Debian / Ubuntu
|
||||
^^^^^^^^^^^^^^^
|
||||
|
||||
Install Vagrant, Git and VirtualBox::
|
||||
|
||||
$ sudo apt-get install -y vagrant git
|
||||
$ sudo apt-get install -y virtualbox-6.1
|
||||
|
||||
If VirtualBox 6.1 was not available in the official packages for
|
||||
your release, follow the instructions at
|
||||
https://www.virtualbox.org/wiki/Linux_Downloads to install it.
|
||||
|
||||
|
||||
Windows
|
||||
^^^^^^^
|
||||
|
||||
Install Vagrant via the ``.msi`` available from
|
||||
https://www.vagrantup.com/downloads.html.
|
||||
|
||||
Install VirtualBox for **Windows hosts** from
|
||||
https://www.virtualbox.org/wiki/Downloads.
|
||||
|
||||
You will also need to install an SSH client, and Git. Git for
|
||||
Windows also comes with an SSH client so just install Git from
|
||||
https://git-scm.com/download/win.
|
||||
|
||||
|
||||
Clone this repository
|
||||
---------------------
|
||||
|
||||
This repository contains the ``Vagrantfile`` that is used for the
|
||||
workshop, which you will need locally.
|
||||
|
||||
::
|
||||
|
||||
$ git clone https://github.com/freeipa/freeipa.git
|
||||
$ cd freeipa/doc/workshop
|
||||
|
||||
|
||||
Fetch Vagrant box
|
||||
-----------------
|
||||
|
||||
Please fetch the Vagrant box prior to the workshop. It is > 700MB
|
||||
so it may not be feasible to download it during the workshop.
|
||||
|
||||
::
|
||||
|
||||
$ vagrant box add freeipa/freeipa-workshop
|
||||
|
||||
|
||||
Add hosts file entries
|
||||
----------------------
|
||||
|
||||
*This step is optional. All units can be completed using the CLI
|
||||
only. But if you want to access the FreeIPA Web UI or other web
|
||||
servers on the VMs from your browser, follow these instructions.*
|
||||
|
||||
Add the following entries to your hosts file::
|
||||
|
||||
192.168.33.10 server.ipademo.local
|
||||
192.168.33.11 replica.ipademo.local
|
||||
192.168.33.20 client.ipademo.local
|
||||
|
||||
On Unix systems (including Mac OS X), the hosts file is ``/etc/hosts``
|
||||
(you need elevated permissions to edit it.)
|
||||
|
||||
On Windows, edit ``C:\Windows\System32\system\drivers\etc\hosts`` as
|
||||
*Administrator*.
|
||||
|
||||
|
||||
Next step
|
||||
---------
|
||||
|
||||
You are ready to begin the workshop. Continue to
|
||||
:ref:`Unit 1: Installing the FreeIPA server <1-server-install>`.
|
||||
|
||||
|
||||
After the workshop
|
||||
------------------
|
||||
|
||||
Here are some contact details and resources that may help you after
|
||||
the workshop is over:
|
||||
|
||||
- IRC: ``#freeipa`` and ``#sssd`` (Libera.chat)
|
||||
|
||||
- ``freeipa-users@lists.fedorahosted.org`` `mailing list
|
||||
<https://lists.fedoraproject.org/archives/list/freeipa-users@lists.fedorahosted.org/>`_
|
||||
|
||||
- `How To guides <https://www.freeipa.org/page/HowTos>`_: large
|
||||
index of articles about specialised tasks and integrations
|
||||
|
||||
- `Troubleshooting guide
|
||||
<https://www.freeipa.org/page/Troubleshooting>`_: how to debug
|
||||
common problems; how to report bugs
|
||||
|
||||
- `Bug tracker <https://pagure.io/freeipa>`_
|
||||
|
||||
- Information about the `FreeIPA public demo
|
||||
<https://www.freeipa.org/page/Demo>`_ instance
|
||||
|
||||
- `Deployment Recommendations
|
||||
<https://www.freeipa.org/page/Deployment_Recommendations>`_:
|
||||
things to consider when going into production
|
||||
|
||||
- `Documentation index
|
||||
<https://www.freeipa.org/page/Documentation>`_
|
||||
|
||||
- `FreeIPA Planet <http://planet.freeipa.org/>`_: aggregate of
|
||||
several FreeIPA and identity-management related blogs
|
||||
|
||||
- `GitHub organisation <https://github.com/freeipa>`_. In addition
|
||||
to the `main repository <https://github.com/freeipa/freeipa>`_
|
||||
there are various tools, CI-related projects and documentation.
|
||||
|
||||
- `Development roadmap <https://www.freeipa.org/page/Roadmap>`_
|
||||
Reference in New Issue
Block a user