github.com/choria-io/go-choria@v0.28.1-0.20240416190746-b3bf9c7d5a45/docs/content/previews/protov2/_index.md (about)

     1  +++
     2  title = "V2 Protocol & Security"
     3  toc = true
     4  weight = 10
     5  pre = "<b>1. </b>"
     6  +++
     7  
     8  This is a guide for early adopters who wish to test and study the [Version 2 Protocol and Security](/adr/001/) project.
     9  
    10  {{% notice warning %}}
    11  This is a *Hard Mode* guide that does everything manually and with no Configuration Management.
    12  {{% /notice %}}
    13  
    14  ### Requirements
    15  
    16   * Choria Nightly
    17   * [Choria AAA Service](https://choria-io.github.io/aaasvc/) Nightly
    18   * [Choria Provisioner](https://choria-io.github.io/provisioner/) Nightly
    19   * Docker on Intel CPU
    20  
    21  ### Security Credentials
    22  
    23  Security is by means of a ed25519 key that signs JWTs, some JWTs form a chain and can sign others. Regardless of the signer verification can be done using the public key associated with the Organization Issuer.
    24  
    25  ![Chain Issuers](/org-issuers.png)
    26  
    27  The Organization Issuer can be kept offline with Provisioning and AAA being delegated authorities capable of signing servers and clients but these are optional components - the Organization Issuer can directly sign Clients and Servers allowing them to operate without the other central components.
    28  
    29  ### Deployment Methods
    30  
    31  We demonstrate two deployment methods:
    32  
    33   * [Decentralized](#decentralized-deployment) - like traditional Choria with only a broker as shared component
    34   * [Centralized AAA and Provisioning](#self-provisioned-and-aaa-integrated-deployment) - uses Choria AAA Service and Choria Provisioner for low-touch auto enrolment of Clients and Servers
    35  
    36  Additionally, we show how Hashicorp Vault can be integrated to [manage the Organization Issuer](#vault-as-organization-issuer)
    37  
    38  {{% notice tip %}}
    39  We recommend reviewers really dig into the details here, we do have a [Docker Compose environment](https://github.com/ripienaar/choria-compose) with this all setup.
    40  {{% /notice %}}
    41  
    42  ### Decentralized deployment
    43  
    44  In this model we will deploy a system that resembles the basic architecture diagram below
    45  
    46  ![Architecture](https://choria.io/docs/basic_client_server_overview.png)
    47  
    48  We have only the Brokers as central architecture with no Central AAA or Provisioning. 
    49  
    50  We will not use mTLS in this case. mTLS is supported but a major advantage of this mode is that it's not required.
    51  
    52  #### Docker
    53  
    54  We will need two Docker networks and 3 instances - broker, server, client and issuer.
    55  
    56  ```nohighlight
    57  $ docker network create choria_v2proto
    58  $ docker network create choria_issuer
    59  $ docker pull registry.choria.io/choria-nightly/choria:nightly
    60  $ docker run -ti --rm --entrypoint bash \
    61        --network choria_v2proto \
    62        --hostname broker.example.net \
    63        registry.choria.io/choria-nightly/choria:nightly -l
    64  $ docker run -ti --rm --entrypoint bash \
    65        --network choria_v2proto \
    66        --hostname server.example.net \
    67        registry.choria.io/choria-nightly/choria:nightly -l
    68  $ docker run -ti --rm --entrypoint bash \
    69        --network choria_v2proto \
    70        --hostname client.example.net \
    71        registry.choria.io/choria-nightly/choria:nightly -l
    72  $ docker run -ti --rm --entrypoint bash \
    73        --network choria_issuer \
    74        --hostname issuer.example.net registry.choria.io/choria-nightly/choria:nightly -l
    75  ```
    76  
    77  The issuer is not needed per-se but will demonstrate that the Issuer credentials never need to near the managed network.
    78  
    79  #### Keys and JWTs
    80  
    81  In this Scenario we need:
    82  
    83   * An Organization Issuer keypair
    84   * A client JWT for each user
    85   * A server JWT for each server
    86   * x509 certificate for the broker TLS port
    87  
    88  In this scenario you are responsible for creating and distributing the keys and tokens.
    89  
    90  ##### Organization Issuer
    91  
    92  The Organization Issuer is the root of the Trust Chain and is a ed25519 key, let's create the keypair on the issuer node:
    93  
    94  ```nohighlight
    95  [choria@issuer ~]$ mkdir -p development/issuer
    96  [choria@issuer ~]$ choria jwt keys development/issuer/private.key development/issuer/public.key
    97  Public Key: b3989a299278750427b00213693c2ca02146476a361667682446230842836da8
    98  
    99  Ed25519 seed saved in development/issuer/private.key
   100  ```
   101  
   102  {{% notice warning %}}
   103  This key should be kept private and ideally in a Hashicorp Vault server. See a later section for guidance on Vault.
   104  {{% /notice %}}
   105  
   106  ##### Broker JWT and Config
   107  
   108  Every broker needs a ed25519 Keypair and a signed JWT.
   109  
   110  First we create a keypair on the broker, the private key never leaves the broker:
   111  
   112  ```nohighlight
   113  [choria@broker ~]$ choria jwt keys /etc/choria/private.key /etc/choria/public.key
   114  Public Key: 8918c1c7a4aeb4d4ad16729dc9b9c12df021d9296106eb5f072b224aa8f8eee9
   115  
   116  Ed25519 seed saved in /etc/choria/private.key
   117  ```
   118  
   119  Pass the Public Key to the Organization Issuer who creates a JWT:
   120  
   121  ```nohighlight
   122  [choria@issuer ~]$ mkdir -p development/broker/broker.example.net
   123  [choria@issuer ~]$ choria jwt server development/broker/broker.example.net/token.jwt \
   124  broker.example.net \
   125  8918c1c7a4aeb4d4ad16729dc9b9c12df021d9296106eb5f072b224aa8f8eee9 \
   126  development/issuer/private.key \
   127  --collectives=choria
   128  ```
   129  
   130  With access to just the Broker public key the Organization Issuer can create a server token, pass this back to the server who stores it in `/etc/choria/broker.jwt`.
   131  
   132  {{% notice tip %}}
   133  Note that for version 2 protocol the default collective is `["choria"]`.
   134  {{% /notice %}}
   135  
   136  ```nohighlight
   137  [choria@issuer ~]$ choria jwt development/broker/broker.example.net/token.jwt development/issuer/public.key
   138  Validated Server Token development/server/server.example.net/token.jwt
   139  
   140               Identity: server.example.net
   141             Expires At: 2023-12-08 13:03:23 +0000 UTC (364d23h59m41s)
   142            Collectives: choria
   143             Public Key: 8918c1c7a4aeb4d4ad16729dc9b9c12df021d9296106eb5f072b224aa8f8eee9
   144      Organization Unit: choria
   145     Private Network ID: 92328d88bef9d063480fd4b0ec5e4879
   146  
   147     Broker Permissions:
   148  
   149            No server specific permissions granted
   150  ```
   151  
   152  We pass the JWT back to the broker and save in `/etc/choria/broker.jwt`.
   153  
   154  The broker need x509 certificates to open the TLS network port, here we just self-sign one but you can get those from anywhere.
   155  
   156  ```nohighlight
   157  [choria@broker ~]$ openssl genrsa -out /etc/choria/broker-tls.key 2048
   158  Generating RSA private key, 2048 bit long modulus (2 primes)
   159  ..+++++
   160  ....................................................................................................+++++
   161  e is 65537 (0x010001)
   162  [choria@broker ~]$ openssl req -new -x509 -sha256 -key /etc/choria/broker-tls.key \
   163     -out /etc/choria/broker-tls.cert -days 365 -subj "/O=Choria.io/CN=broker.example.net"
   164  ```
   165  
   166  With all in place it should look like this:
   167  
   168  ```nohighlight
   169  [choria@broker ~]$ find /etc/choria/
   170  /etc/choria/
   171  /etc/choria/broker.conf
   172  /etc/choria/broker-tls.key
   173  /etc/choria/broker-tls.cert
   174  /etc/choria/private.key
   175  /etc/choria/public.key
   176  /etc/choria/broker.jwt
   177  ```
   178  
   179  We create the broker configuration in `/etc/choria/broker.conf` and start it, you need to change your issuer here:
   180  
   181  ```nohighlight
   182  # The name of the organization to configure, for now only supports choria
   183  plugin.security.issuer.names = choria
   184  
   185  # The public key from the issuer
   186  plugin.security.issuer.choria.public = b3989a299278750427b00213693c2ca02146476a361667682446230842836da8
   187  
   188  # Configures access to broker internal statistics and more
   189  plugin.choria.network.system.password = sYst3m
   190  
   191  # Used later in the Provisioner based setup
   192  plugin.choria.network.provisioning.client_password = s3cret
   193  
   194  plugin.choria.stats_port = 8222
   195  plugin.choria.broker_network = true
   196  plugin.choria.network.client_port = 4222
   197  plugin.choria.network.stream.store = /data
   198  plugin.choria.network.system.user = system
   199  loglevel = info
   200  plugin.choria.use_srv = false
   201  
   202  plugin.security.provider = choria
   203  plugin.security.choria.certificate = /etc/choria/broker-tls.cert
   204  plugin.security.choria.key = /etc/choria/broker-tls.key
   205  plugin.security.choria.token_file = /etc/choria/broker.jwt
   206  plugin.security.choria.seed_file = /etc/choria/private.key
   207  ```
   208  
   209  Let's start the broker, showing the key lines from the output here:
   210  
   211  ```nohighlight
   212  $ choria broker run --config /etc/choria/broker.conf
   213  INFO[0000] Choria Broker version 0.99.0.20221201 starting with config /etc/choria/broker.conf
   214  INFO[0000] Starting Network Broker
   215  WARN[0000] Allowing unverified TLS connections for Organization Issuer issued connections  component=network
   216  WARN[0000] Loaded Organization Issuer choria with public key b3989a299278750427b00213693c2ca02146476a361667682446230842836da8  component=network
   217  INFO[0000] Listening for client connections on [::]:4222  component=network_broker
   218  ...
   219  ```
   220  
   221  ##### Server JWT
   222  
   223  Every server needs a ed25519 Keypair and a signed JWT.
   224  
   225  The server process is identical to the broker process except change `broker.example.net` to `server.example.net` in identities and make obvious file name changes. Servers do not need any x509 certificates like brokers.
   226  
   227  Now we can configure and start the server, place this in `/etc/choria/server.conf`:
   228  
   229  ```nohighlight
   230  # The name of the organization to configure, for now only supports choria
   231  plugin.security.issuer.names = choria
   232  
   233  # The public key from the issuer
   234  plugin.security.issuer.choria.public = b3989a299278750427b00213693c2ca02146476a361667682446230842836da8
   235  
   236  # We enable authorization and set it to trust the JWT tokens policy
   237  rpcauthorization = 1
   238  rpcauthprovider = aaasvc
   239  
   240  plugin.security.provider = choria
   241  plugin.security.choria.token_file = /etc/choria/server.jwt
   242  plugin.security.choria.seed_file = /etc/choria/private.key
   243  plugin.choria.middleware_hosts = nats://broker.example.net:4222
   244  ```
   245  
   246  And finally let's run the server, showing key log lines only:
   247  
   248  {{% notice tip %}}
   249  Servers usually run as root, here as the `choria` user as it's in the container
   250  {{% /notice %}}
   251  
   252  ```nohighlight
   253  [choria@server ~]$ choria server run --config /etc/choria/server.conf
   254  INFO[0000] Choria Server version 0.99.0.20221201 starting with config /etc/choria/server.conf using protocol version 2
   255  INFO[0000] Setting JWT token and unique reply queues based on JWT for "server.example.net"  component=server connection=server.example.net identity=server.example.net
   256  INFO[0000] Setting custom inbox prefix based on unique ID to choria.reply.77e64440ac709c0836487e5b77334e5b  component=server connection=server.example.net identity=server.example.net
   257  ```
   258  
   259  ###### Client JWT
   260  
   261  Every client needs a ed25519 keypair and a signed JWT.
   262  
   263  We will create a client that has access to Choria Streams and the ability to manage the fleet without any AAA Server.
   264  
   265  The client will create their own keypair, so we run that in the client node:
   266  
   267  ```noghighlight
   268  [choria@client ~]$ mkdir -p ~/.config/choria/
   269  [choria@client ~]$ choria jwt keys ~/.config/choria/private.key ~/.config/choria/public.key
   270  Public Key: 4bbfddb9f70f4b39f5b13bac8e83a9a31c3af49e388da86a666f8615101bc818
   271  
   272  Ed25519 seed saved in /home/choria/.config/choria/private.key
   273  ```
   274  
   275  This client `private.key` should be kept private and not shared, the JWT can be created with knowledge of the public key only.
   276  
   277  The client pass their Public Key to the Organization Issuer who creates a JWT on the Issuer node:
   278  
   279  {{% notice tip %}}
   280  Here we use `choria` as the identity, this would match the unix user name.
   281  
   282  If a user is on many machines, create a JWT per machine.
   283  {{% /notice %}}
   284  
   285  ```nohighlight
   286  [choria@issuer ~]$ mkdir -p development/client/choria
   287  [choria@issuer ~]$ choria jwt client development/client/choria/token.jwt choria development/issuer/private.key \
   288   --public-key 4bbfddb9f70f4b39f5b13bac8e83a9a31c3af49e388da86a666f8615101bc818 \
   289   --stream-admin \
   290   --event-viewer \
   291   --elections-user \
   292   --service \
   293   --fleet-management \
   294   --agents '*' \
   295   --validity 1y
   296  Saved token to development/client/choria/token.jwt, use 'choria jwt view development/client/choria/token.jwt' to view it
   297  ```
   298  
   299  With access to the Issuer private key, but not the user private key, we can create a JWT for the user. Since we have no AAA Service we mark this user as a `service` which allows them to have a long token validity. We set a policy allowing all agent access, in real life this would be an Open Policy Agent policy.
   300  
   301  ```nohighlight
   302  [choria@issuer ~]$ choria jwt development/client/choria/token.jwt development/issuer/public.key
   303  Validated Client Identification Token development/client/choria/token.jwt
   304  
   305            Caller ID: choria
   306    Organization Unit: choria
   307       Allowed Agents: *
   308           Public Key: 4bbfddb9f70f4b39f5b13bac8e83a9a31c3af49e388da86a666f8615101bc818
   309   Private Network ID: 0a63c70a8817f5ef4d19d055ce6513f1
   310           Expires At: 2023-12-08 12:54:07 +0000 UTC (364d23h59m19s)
   311  
   312   Client Permissions:
   313  
   314        Can manage Choria fleet nodes
   315        Can use Leader Elections
   316        Can view Lifecycle and Autonomous Agent events
   317        Can administer Choria Streams
   318        Can access the Broker system account
   319        Can have an extended token lifetime
   320  ```
   321  
   322  Pass the JWT back to the client who saves it in `~/.config/choria/token.jwt`.
   323  
   324  ```nohighlight
   325  [choria@client ~]$ find ~/.config
   326  /home/choria/.config
   327  /home/choria/.config/choria
   328  /home/choria/.config/choria/private.key
   329  /home/choria/.config/choria/public.key
   330  /home/choria/.config/choria/token.jwt
   331  ```
   332  
   333  We create a system-wide client configuration in `/etc/choria/client.conf`:
   334  
   335  ```nohighlight
   336  loglevel = warn
   337  plugin.choria.middleware_hosts = broker.example.net:4222
   338  plugin.choria.network.system.user = system
   339  plugin.choria.network.system.password = sYst3m
   340  
   341  plugin.security.provider = choria
   342  plugin.security.choria.token_file = ~/.config/choria/token.jwt
   343  plugin.security.choria.seed_file = ~/.config/choria/private.key
   344  ```
   345  
   346  We can now test the client:
   347  
   348  ```nohighlight
   349  [choria@client ~]$ choria ping
   350  server.example.net                       time=3 ms
   351  
   352  ---- ping statistics ----
   353  1 replies max: 4ms min: 4ms avg: 4ms overhead: 12ms
   354  ```
   355  
   356  Other commands like `choria req choria_util info` should work demonstrating authorization works and `choria broker server list` should list the broker indicating Broker System Account access works. After a minute or so `choria broker stream ls` will show a list of Streams demonstrating Choria Streams authority worked.
   357  
   358  ### Self Provisioned and AAA Integrated Deployment
   359  
   360  Thus far we had to manually sign and configure every single server and client, we had to copy files around and more, it's all a bit tedious.
   361  
   362  Lets see how Choria can configure itself and how user management can be centralized for self-service user enrollment.
   363  
   364   * Instead of signing Server JWTs servers will go to [Choria Provisioner](https://choria-io.github.io/provisioner/) to obtain credentials and configuration
   365   * Instead of issuing Client JWTs for every user that are long-lasting we will use a central authorization flow to issue short-lived JWTs and distribute them
   366  
   367  ![Centralized Deployment](/protov2-centralized.png)
   368  
   369  #### Docker
   370  
   371  We will create re-use the networks we made before, and we can keep the same `issuer.example.net` and `broker.example.net`.
   372  
   373  So stop and recreate your server and client containers, we'll 2 more container during the guide.
   374  
   375  #### Issuer
   376  
   377  The issuer is unchanged from before, so just follow the same steps as before or keep the one you have if you followed the Decentralized section.
   378  
   379  #### Broker
   380  
   381  The broker is unchanged from before, so just follow the same steps as before or keep the one you have if you followed the earlier Decentralized section.
   382  
   383  You will note we have a setting in the `broker.conf`:
   384  
   385  ```ini
   386  plugin.choria.network.provisioning.client_password = s3cret
   387  ```
   388  
   389  This instructs the broker that we will be connecting servers needing provisioning to it. You should see a log line like:
   390  
   391  ```nohighlight
   392  WARN[0000] Allowing Provisioner connections subject to JWT claims  component=network
   393  ```
   394  
   395  #### Provisioner
   396  
   397  The [Choria Provisioner](https://choria-io.github.io/provisioner/) is a service that configures new Choria Servers:
   398  
   399   * Enrolls servers into the Issuer
   400   * Create a per-node configuration
   401   * Deploys Open Policy Agent policies
   402   * Configures the server
   403   * Optionally perform version upgrades
   404  
   405  We have CLI tooling allowing you to re-provision servers on demand and more. Review its documentation for full detail.
   406  
   407  It needs to connect to the broker, so it needs JWT token, let's create the container and create the private key:
   408  
   409  Since the container does not have the `choria` command we have to jump some hoops, we'll make a local storage directory for its configuration and keys and then mount that in.
   410  
   411  ```nohighlight
   412  host$ mkdir provisioner
   413  host$ docker run -v `pwd`/provisioner:/etc/choria-provisioner --user root --entrypoint bash --rm -ti registry.choria.io/choria-nightly/choria:nightly -l
   414  [root@5d96691fa69f /]# choria jwt keys /etc/choria-provisioner/private.key /etc/choria-provisioner/public.key
   415  Public Key: a8c15c0a4bbae0646d0c5aa92513f4d58c2c0e51464b4b267bb3a42dbebd1c8a
   416  [root@5d96691fa69f /]# chown -R choria:choria /etc/choria-provisioner/
   417  [root@5d96691fa69f /]# exit
   418  ```
   419  
   420  Next we create a provisioner JWT and save it in `provisioner/token.jwt`
   421  
   422  ```nohightlight
   423  [choria@issuer ~]$ mkdir -p development/provisioner
   424  [choria@issuer ~]$ choria jwt client development/provisioner/token.jwt provisioner_signer development/issuer/private.key \
   425      --public-key a8c15c0a4bbae0646d0c5aa92513f4d58c2c0e51464b4b267bb3a42dbebd1c8a \
   426      --server-provisioner \
   427      --validity 365d \
   428      --issuer
   429  ```
   430  
   431  Here we create a token that has access to the NATS Account new machines will join, it's a year valid and it can issue new credentials.
   432  
   433  Place the `development/provisioner/token.jwt` on your host in `provisioner/token.jwt`, next to `private.key` and `public.key` we made above.
   434  
   435  {{% notice tip %}}
   436  We will not delve much into the Provisioner configuration details, [visit its documentation site](https://choria-io.github.io/provisioner/) for details.
   437  {{% /notice %}}
   438  
   439  We need to configure how the Provisioner use these files, create `provisioner/client.cfg` on your host:
   440  
   441  ```ini
   442  plugin.security.provider = choria
   443  plugin.security.choria.token_file = /etc/choria-provisioner/token.jwt
   444  plugin.security.choria.seed_file = /etc/choria-provisioner/private.key
   445  
   446  identity = provisioner_signer
   447  
   448  plugin.choria.middleware_hosts = nats://broker.example.net:4222
   449  ```
   450  
   451  Next we create the Provisioner configuration file in `provisioner/choria-provisioner.yaml`:
   452  
   453  ```yaml
   454  # The issuer public key
   455  jwt_verify_cert: b3989a299278750427b00213693c2ca02146476a361667682446230842836da8
   456  interval: 1m
   457  logfile: /dev/stdout
   458  loglevel: info
   459  helper: /etc/choria-provisioner/helper.rb
   460  token: s3cret
   461  choria_insecure: false
   462  site: PREVIEW
   463  broker_provisioning_password: s3cret
   464  jwt_signing_key: private.key
   465  jwt_signing_token: token.jwt
   466  
   467  features:
   468    jwt: true
   469    ed25519: true
   470  ```
   471  
   472  Next we need the script that generates per-node configuration, store the [helper.rb](helper.rb) in `provisioner/helper.rb` and change the `ISSUER` constant near the top.
   473  
   474  ```nohightlight
   475  host$ vi provisioner/helper.rb
   476  host$ chmod a+x provisioner/helper.rb
   477  host$ sudo chown -R 2048:2048 provisioner
   478  ```
   479  
   480  We can now run our Provisioner:
   481  
   482  ```nohighlight
   483  host$ docker run -ti --rm -v `pwd`/provisioner:/etc/choria-provisioner \
   484      --network choria_v2proto \
   485      --hostname provisioner.example.net \
   486      choria/provisioner:nightly
   487  ```
   488  
   489  #### Servers
   490  
   491  For servers, we are going to need the RPM (already in the container) and a new file `/etc/choria/provisioning.jwt`.  This is read by the server process and tells it to enter provisioning mode.
   492  
   493  The JWT file is basically just a configuration file signed by our Issuer.  The server reads it unvalidated but the Provisioner will ensure the incoming server holds the token signed by our Issuer.
   494  
   495  ```nohighlight
   496  [choria@issuer ~]$ choria jwt prov development/server/provisioning.jwt \
   497      development/issuer/private.key \
   498      --token s3cret \
   499      --urls nats://broker.example.net:4222 \
   500      --protocol-v2 \
   501      --default
   502  Saved token to development/server/provisioning.jwt, use 'choria jwt view development/server/provisioning.jwt' to view it
   503  
   504  [choria@issuer ~]$ choria jwt development/server/provisioning.jwt
   505  Unvalidated Provisioning Token development/server/provisioning.jwt
   506  
   507                           Token: *****
   508                          Secure: false
   509                            URLS: nats://broker.example.net:4222
   510         Provisioning by default: true
   511        Using version 2 Protocol: true
   512         Server Version Upgrades: false
   513                 Standard Claims: {
   514                                    "purpose": "choria_provisioning",
   515                                    "iss": "Choria Tokens Package v0.99.0.20221210",
   516                                    "sub": "choria_provisioning",
   517                                    "nbf": 1670850426,
   518                                    "iat": 1670850426,
   519                                    "jti": "60a2973b10304184b997f9ea50eeb7a4"
   520                                  }
   521  ```
   522  
   523  Copy this to your host before running the server. We need to mount this token into the server containers, no other configuration is needed:
   524  
   525  ```nohighlight
   526  host$ docker run -ti --rm \
   527        --network choria_v2proto \ 
   528        --hostname server.example.net \
   529        -v `pwd`/provisioning.jwt:/etc/choria/provisioning.jwt \
   530        registry.choria.io/choria-nightly/choria:nightly server run --config /etc/choria/server.conf
   531  ```
   532  
   533  The server will now start and connect to the Broker, communicate with the Provisioner and restart itself.  After restart
   534  the client (configured next) will be able to communicate with it.
   535  
   536  Previously we had to use `choria jwt keys` and `choria jwt server` to create Private keys and to issue a signed JWT and then manually transfer that to the Server and configure the Server.  This all happens under Choria Provisioner control and takes just a few milliseconds. The only site-unique part about a machine is now the `provisioner.jwt` that is shared by your fleet, so it's easily placed there during base image build or configuration management. You could issue node-unique `provisioning.jwt` files with extended information in them and in your `helper.rb` perform additional validation if you needed that much control.
   537  
   538  #### AAA Service
   539  
   540  To provide a self-service system for Clients configure the [Choria AAA Service](https://choria-io.github.io/aaasvc/). Here we will configure it to both issue JWTs and Sign individual requests - meaning it's required to be available for every RPC request.  The signing part is optional though, and we could skip that, using it only to obtain JWT tokens.
   541  
   542  {{% notice tip %}}
   543  We will not delve much into the AAA Service configuration details, [visit its documentation site](https://choria-io.github.io/aaasvc/configuration/org-issuer/) for details.
   544  {{% /notice %}}
   545  
   546  We need to issue 3 sets of credentials here:
   547  
   548   * One to sign users who request their JWT using `choria login` called the *Chain Signer*, since this is HTTP it also needs a x509 certificate
   549   * One to sign RPC requests on behalf of users after evaluating policies and auditing requests called the *Request Signer*
   550   * One to connect to Choria Broker with and run a Choria RPC Service that will receive requests from users to sign their requests called a *Signer Service*.
   551  
   552  Like the Provisioner the AAA Service container does not have the `choria` binary, so we need to jump some hoops to make the keys and configuration:
   553  
   554  ```nohighlight
   555  host$ docker run -ti --rm -v `pwd`/aaasvc:/etc/aaasvc --user root --entrypoint bash registry.choria.io/choria-nightly/choria:nightly -l
   556  [root@38f75c90e475 /]# openssl genrsa -out /etc/aaasvc/https-private.key 2048
   557  Generating RSA private key, 2048 bit long modulus (2 primes)
   558  ........................................................................................+++++
   559  ...................................+++++
   560  [root@38f75c90e475 /]# openssl req -new -x509 -sha256 -key /etc/aaasvc/https-private.key -out /etc/aaasvc/https-public.crt -days 365 -subj "/O=Choria.io/CN=aaa.choria.local"
   561  [root@38f75c90e475 /]# choria jwt keys /etc/aaasvc/chain-signer-private.key /etc/aaasvc/chain-signer-public.key
   562  Public Key: 17807f2c5fa959383ee5851813863426525c081f6464556e5dec482e815caded
   563  
   564  Ed25519 seed saved in /etc/aaasvc/chain-signer-private.key
   565  ```
   566  
   567  We create a self-signed x509 certificate since the Authentication service runs over HTTPS, you can use any certificate for this.
   568  
   569  Further we create a key used to sign JWTs for users running `choria login`, it needs a special JWT:
   570  
   571  ```nohighlight
   572  [choria@issuer ~]$ mkdir -p development/aaasvc
   573  [choria@issuer ~]$ choria jwt client development/aaasvc/chain-signer.jwt aaa_chain_signer \
   574      development/issuer/private.key \
   575      --public-key  17807f2c5fa959383ee5851813863426525c081f6464556e5dec482e815caded \
   576      --no-fleet-management \
   577      --issuer \
   578      --validity 365d
   579  Saved token to client development/aaasvc/chain-signer.jwt, use 'choria jwt view client development/aaasvc/chain-signer.jwt' to view it
   580  ```
   581  
   582  Copy this file to the temporary AAA container above as `/etc/aaasvc/chain-signer.jwt`.
   583  
   584  Next we create the credentials that will sign every RPC request:
   585  
   586  ```nohighlight
   587  host$ docker run -ti --rm -v `pwd`/aaasvc:/etc/aaasvc --user root --entrypoint bash registry.choria.io/choria-nightly/choria:nightly -l
   588  [root@38f75c90e475 /]# choria jwt keys /etc/aaasvc/request-signer-private.key /etc/aaasvc/reqeuest-signer-public.key
   589  Public Key: 535e9d337e555b9bf9079269567b8d9cb812fdf54797e5d5441ed778f1db68d8
   590  
   591  Ed25519 seed saved in /etc/aaasvc/request-signer-private.key
   592  ```
   593  
   594  This is the key used to sign individual user RPC requests on their behalf, it needs a special JWT:
   595  
   596  ```nohighlight
   597  [choria@issuer ~]$ mkdir -p development/aaasvc
   598  [choria@issuer ~]$ choria jwt client development/aaasvc/request-signer.jwt aaa_request_signer \
   599      development/issuer/private.key \
   600      --public-key 535e9d337e555b9bf9079269567b8d9cb812fdf54797e5d5441ed778f1db68d8 \
   601      --no-fleet-management \
   602      --auth-delegation \
   603      --validity 365d
   604  Saved token to development/aaasvc/request-signer.jwt, use 'choria jwt view development/aaasvc/request-signer.jwt' to view it
   605  ```
   606  
   607  Place it in `/etc/aaasvc/request-signer.jwt` on the AAA Service container above.
   608  
   609  Finally, we need to create the credentials that allow the request signer to run as a Choria Service. 
   610  
   611  ```nohighlight
   612  host$ docker run -ti --rm -v `pwd`/aaasvc:/etc/aaasvc --user root --entrypoint bash registry.choria.io/choria-nightly/choria:nightly -l
   613  [root@38f75c90e475 /]# choria jwt keys /etc/aaasvc/signer-service-private.key /etc/aaasvc/signer-service-public.key
   614  Public Key: c5c1323f66bb8324d019249e3476d9f11f9deb70efa60255593dde30ef3b8a01
   615  
   616  Ed25519 seed saved in /etc/aaasvc/signer-service-private.key
   617  ```
   618  
   619  Let's create the `server` JWT that will host the RPC Service for signing requests
   620  ```nohighlight
   621  [choria@issuer ~]$ choria jwt server development/aaasvc/signer-service.jwt \
   622      aaa.example.net \
   623      c5c1323f66bb8324d019249e3476d9f11f9deb70efa60255593dde30ef3b8a01 \
   624      development/issuer/private.key \
   625      --org choria \
   626      --collectives choria \
   627      --service \
   628      --validity 365d
   629  ```
   630  
   631  Place it in `/etc/aaasvc/signer-service.jwt` on the AAA Service container above.
   632  
   633  We can now configure the various parts of the AAA Service, it needs a `/etc/aaasvc/choria.conf` to connect to the network with:
   634  
   635  ```ini
   636  identity = aaa.example.net
   637  plugin.security.provider = choria
   638  plugin.security.choria.seed_file = /etc/aaasvc/signer-service-private.key
   639  plugin.security.choria.token_file = /etc/aaasvc/signer-service.jwt
   640  plugin.choria.middleware_hosts = broker.example.net:4222
   641  ```
   642  
   643  We need an `/etc/aaasvc/aaasvc.conf`:
   644  
   645  {{% notice tip %}}
   646  See the [User List Authenticator docs](https://choria-io.github.io/aaasvc/configuration/userlist/index.html) about user, passwords and more.  The passwords below are all `secret`.
   647  {{% /notice %}}
   648  
   649  ```json
   650  {
   651    "choria_config": "/etc/aaasvc/choria.conf",
   652    "logfile": "/dev/stdout",
   653    "loglevel": "info",
   654    "authenticator": "userlist",
   655    "authorizer": "opa",
   656    "signer": "basicjwt",
   657    "monitor_port": 8081,
   658    "site": "PREVIEW",
   659    "tls_certificate": "/etc/aaasvc/https-public.crt",
   660    "tls_key":"/etc/aaasvc/https-private.key",
   661    "port":8080,
   662    "basicjwt_signer": {
   663      "signing_certificate": "/etc/aaasvc/chain-signer-public.key",
   664      "signing_token": "/etc/aaasvc/request-signer.jwt",
   665      "signing_seed": "/etc/aaasvc/request-signer-private.key",
   666      "max_validity":"2h",
   667      "choria_service": true
   668    },
   669    "userlist_authenticator": {
   670      "signing_key": "/etc/aaasvc/chain-signer-private.key",
   671      "signing_token": "/etc/aaasvc/chain-signer.jwt",
   672      "validity": "1h",
   673      "users": [
   674      {
   675        "username": "admin",
   676        "password": "$2a$05$zQIl4gUZbqmKhpQhIeWx3uDWhAZaHoG34zW1ZsxXQt5xpL5f4uyny",
   677        "opa_policy_file": "/etc/aaasvc/admin.rego",
   678        "broker_permissions": {
   679          "org_admin": true,
   680          "system_user": true,
   681          "signed_fleet_management": true
   682        }
   683      },
   684      {
   685        "username": "streams",
   686        "password": "$2a$05$zQIl4gUZbqmKhpQhIeWx3uDWhAZaHoG34zW1ZsxXQt5xpL5f4uyny",
   687        "broker_permissions": {
   688          "streams_admin": true
   689        }
   690      },
   691      {
   692        "username": "choria",
   693        "password": "$2a$05$zQIl4gUZbqmKhpQhIeWx3uDWhAZaHoG34zW1ZsxXQt5xpL5f4uyny",
   694        "opa_policy_file": "/etc/aaasvc/admin.rego",
   695        "broker_permissions": {
   696          "signed_fleet_management": true
   697        }
   698      }
   699      ]
   700    }
   701  }
   702  ```
   703  
   704  {{% notice warning %}}
   705  See the [AAA Service Docs](https://choria-io.github.io/aaasvc/configuration/opa/) for writing real policies.
   706  {{% /notice %}}
   707  
   708  Finally, we create an Open Policy Agent policy for the Choria Users, this one just allows everything. Place it in `/etc/aaasvc/admin.rego`
   709  
   710  ```opa
   711  package io.choria.aaasvc
   712  
   713  default allow = true
   714  ```
   715  
   716  We can now start the AAA Service:
   717  
   718  ```nohightlight
   719  host$ sudo chown -R 2048:2048 aaasvc
   720  host$ docker run -ti --rm \
   721      -v `pwd`/aaasvc:/etc/aaasvc \
   722      --network choria_v2proto \
   723      --hostname aaa.example.net \
   724      choria/aaasvc:nightly run --config /etc/aaasvc/aaasvc.conf 
   725  ```
   726  
   727  #### Client
   728  
   729  Choria Clients will now enroll using `choria login` which will issue them a 1-hour valid JWT with their policies and more embedded.
   730  
   731  Lets create a new client container:
   732  
   733  ```nohighlight
   734  $ docker run -ti --rm --entrypoint bash \
   735        --network choria_v2proto \
   736        --hostname client.example.net \
   737        registry.choria.io/choria-nightly/choria:nightly -l
   738  ```
   739  
   740  We create a system-wide client configuration in `/etc/choria/client.conf`:
   741  
   742  ```nohighlight
   743  loglevel = warn
   744  plugin.choria.middleware_hosts = broker.example.net:4222
   745  plugin.choria.network.system.user = system
   746  plugin.choria.network.system.password = sYst3m
   747  
   748  plugin.security.provider = choria
   749  plugin.security.choria.token_file = ~/.config/choria/client.jwt
   750  plugin.security.choria.seed_file = ~/.config/choria/client.key
   751  plugin.choria.security.request_signer.service = true
   752  plugin.login.aaasvc.login.url = https://aaa.example.net:8080/choria/v1/login
   753  ```
   754  
   755  Users can now run `choria login` and authenticate using on of the usernames and the password `secret`.
   756  
   757  The client is now entirely self-service, the token expires every hour, and they just run `choria login` again.  They can do this on as many machines as they have and admins do not get involved.
   758  
   759  Every RPC request the client makes will be signed by the AAA Service after Authorization against the OPA Policy and auditing the outcome.  Servers will also validate the OPA policy before executing anything.
   760  
   761  ### Vault as Organization Issuer
   762  
   763  We support using [Hashicorp Vault](https://www.vaultproject.io/) as the Organization Issuer.  In that mode the Private Key is created inside Vault and never has to leave Vault at all.
   764  
   765  {{% notice warning %}}
   766  Here we'll show the developer mode Vault you should use a Production deployment of Vault and not a simple developer local build.
   767  {{% /notice %}}
   768  
   769  #### Starting Vault
   770  
   771  We start Vault in dev mode with a static secret defined:
   772  
   773  ```nohighlight
   774  $ vault server -dev -dev-root-token-id root
   775  ==> Vault server configuration:
   776  
   777               Api Address: http://127.0.0.1:8200
   778                       Cgo: disabled
   779           Cluster Address: https://127.0.0.1:8201
   780  ....
   781  WARNING! dev mode is enabled! In this mode, Vault runs entirely in-memory
   782  and starts unsealed with a single unseal key. The root token is already
   783  authenticated to the CLI, so you can immediately begin using Vault.
   784  
   785  You may need to set the following environment variables:
   786  
   787      $ export VAULT_ADDR='http://127.0.0.1:8200'
   788  
   789  The unseal key and root token are displayed below in case you want to
   790  seal/unseal the Vault or re-authenticate.
   791  
   792  Unseal Key: JKyF70iBqv3d9rreY9rhY0/EQ9ornriTZHV+kVWpJ+w=
   793  Root Token: root
   794  
   795  Development mode should NOT be used in production installations!
   796  ```
   797  
   798  #### Configuring the Transit Secrets Engine
   799  
   800  Choria relies on the [Transit Secrets Engine](https://developer.hashicorp.com/vault/docs/secrets/transit) to offload signing of keys.
   801  
   802  Let's enable that:
   803  
   804  ```nohighlight
   805  $ export VAULT_ADDR='http://127.0.0.1:8200
   806  $ export VAULT_TOKEN='root'
   807  $ vault secrets enable transit
   808  Success! Enabled the transit secrets engine at: transit/
   809  ```
   810  
   811  #### Create the Issuer
   812  
   813  We use the Vault API to create an `ed25519` key stored in Vault storage:
   814  
   815  ```nohighlight
   816  $ export VAULT_ADDR='http://127.0.0.1:8200
   817  $ export VAULT_TOKEN='root'
   818  $ vault write transit/keys/choria_issuer type=ed25519
   819  Success! Data written to: transit/keys/choria_issuer
   820  $ vault read transit/keys/choria_issuer
   821  Key                       Value
   822  ---                       -----
   823  allow_plaintext_backup    false
   824  auto_rotate_period        0s
   825  deletion_allowed          false
   826  derived                   false
   827  exportable                false
   828  imported_key              false
   829  keys                      map[1:map[creation_time:2022-12-12T11:21:23.248802439+01:00 name:ed25519 public_key:IZu6TyYAwWeuyD3Q0tEiCGbYBjkRjoOcWO/OI9PDmOE=]]
   830  latest_version            1
   831  min_available_version     0
   832  min_decryption_version    1
   833  min_encryption_version    0
   834  name                      choria_issuer
   835  supports_decryption       false
   836  supports_derivation       true
   837  supports_encryption       false
   838  supports_signing          true
   839  type                      ed25519
   840  ```
   841  
   842  Here we see that the public key is shown as `public_key:IZu6TyYAwWeuyD3Q0tEiCGbYBjkRjoOcWO/OI9PDmOE=`, lets turn that into a hex encoded string:
   843  
   844  {{% notice tip %}}
   845  If saving the public key to a file ensure there is no trailing new line
   846  {{% /notice %}}
   847  
   848  ```nohighlight
   849  $ echo IZu6TyYAwWeuyD3Q0tEiCGbYBjkRjoOcWO/OI9PDmOE=|base64 -d|xxd -p -c 64
   850  219bba4f2600c167aec83dd0d2d1220866d80639118e839c58efce23d3c398e1
   851  ```
   852  
   853  This is the Organization Issuer you configure in your broker and elsewhere.
   854  
   855  #### Signing JWTs using Vault
   856  
   857  The `choria jwt` commands support the `--vault` flag that requires `VAULT_ADDR` and `VAULT_TOKEN` to be set in environment.
   858  
   859  ```nohighlight
   860  $ choria jwt server \
   861      token.jwt \
   862      server.example.net \
   863      3f2d5d01f3c5caa0cd7359512c7e2d9a727fa0392f47f50adee1866bf02cbe12 \
   864      choria_issuer \
   865      --collectives=choria \
   866      --vault
   867  ```
   868  
   869  Here we pass `--vault` and instead of a path to the Issuer Private Key we give the name `choria_issuer` that we created in Vault.