Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 19 additions & 0 deletions ocaml/idl/datamodel_errors.ml
Original file line number Diff line number Diff line change
Expand Up @@ -904,6 +904,25 @@ let _ =
"The host joining the pool must have one and only one IP on the \
clustering network"
() ;
error Api_errors.pool_joining_host_tls_verification_mismatch []
~doc:
"The TLS verification check failed when the joining host attempted to \
open a verified connection to the pool coordinator using the imported \
pool certificate bundle."
() ;
error Api_errors.pool_joining_master_certificate_not_in_pool_bundle
["master_uuid"]
~doc:
"The pool coordinator's own certificate is absent from the pool \
certificate bundle sent to the joining host. Run 'xe \
pool-certificate-sync' on the coordinator and retry."
() ;
error Api_errors.pool_joining_pool_bundle_empty_after_import ["bundle_path"]
~doc:
"The pool certificate bundle is empty or missing after import on the \
joining host. The bundle generation script (update-ca-bundle.sh) likely \
failed silently."
() ;

(* External directory service *)
error Api_errors.subject_cannot_be_resolved []
Expand Down
6 changes: 6 additions & 0 deletions ocaml/xapi-consts/api_errors.ml
Original file line number Diff line number Diff line change
Expand Up @@ -748,6 +748,12 @@ let pool_joining_host_has_network_sriovs =
let pool_joining_host_tls_verification_mismatch =
add_error "POOL_JOINING_HOST_TLS_VERIFICATION_MISMATCH"

let pool_joining_master_certificate_not_in_pool_bundle =
add_error "POOL_JOINING_MASTER_CERTIFICATE_NOT_IN_POOL_BUNDLE"

let pool_joining_pool_bundle_empty_after_import =
add_error "POOL_JOINING_POOL_BUNDLE_EMPTY_AFTER_IMPORT"

Comment thread
last-genius marked this conversation as resolved.
let pool_joining_host_ca_certificates_conflict =
add_error "POOL_JOINING_HOST_CA_CERTIFICATES_CONFLICT"

Expand Down
24 changes: 23 additions & 1 deletion ocaml/xapi/cert_distrib.ml
Original file line number Diff line number Diff line change
Expand Up @@ -704,7 +704,29 @@ let exchange_certificates_with_joiner ~__context ~uuid ~certificate =
let import_joining_pool_certs ~__context ~pool_certs =
let pool_certs = List.map WireProtocol.certificate_file_of_pair pool_certs in
Worker.local_write_cert_fs ~__context HostPoolCert Merge pool_certs ;
Worker.local_regen_bundle ~__context
Worker.local_regen_bundle ~__context ;
(* update-ca-bundle.sh can fail silently, leaving an empty bundle that would
cause an opaque Stunnel_verify_error when the verified connection is
opened in Phase 2 of the join. *)
let bundle_path = !Xapi_globs.pool_bundle_path in
let bundle_empty_or_missing =
match Unix.stat bundle_path with
| exception Unix.Unix_error (Unix.ENOENT, _, _) ->
true
| stats ->
stats.Unix.st_size = 0
in
if bundle_empty_or_missing then (
D.error
"import_joining_pool_certs: pool bundle '%s' is empty or missing after \
certificate import. The bundle generation script \
(/opt/xensource/bin/update-ca-bundle.sh) likely failed silently."
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does the script leave some errors in daemon.log to be able to investigate? or is the failure actually silent?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

#!/bin/bash
#
# Copyright (c) Citrix Systems 2008. All rights reserved.
#

set -e

regen_bundle () {
  CERTS_DIR="$1"
  BUNDLE="$2"

  mkdir -p "$CERTS_DIR"
  CERTS=$(find "$CERTS_DIR" -not -name '*.new.pem' -name '*.pem')
  NEW_CERTS=$(find "$CERTS_DIR" -name '*.new.pem')

  rm -f "$BUNDLE.tmp"
  touch "$BUNDLE.tmp"
  for NEW_CERT in $NEW_CERTS; do
    # If cat new cert command fails, do not error and exit, just skip it
    if cat "$NEW_CERT" >> "$BUNDLE.tmp"; then
      echo "" >> "$BUNDLE.tmp"
    fi
  done
  for CERT in $CERTS; do
    cat "$CERT" >> "$BUNDLE.tmp"
    echo ""     >> "$BUNDLE.tmp"
  done
  mv "$BUNDLE.tmp" "$BUNDLE"
}

regen_bundle "/etc/stunnel/certs"      "/etc/stunnel/xapi-stunnel-ca-bundle.pem"
regen_bundle "/etc/stunnel/certs-pool" "/etc/stunnel/xapi-pool-ca-bundle.pem"

This script is silent...

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

looks like a fairly simple script, I wonder why would cat new cert possibly fail???

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't know..

bundle_path ;
raise
Api_errors.(
Server_error (pool_joining_pool_bundle_empty_after_import, [bundle_path])
)
)

let collect_ca_certs ~__context ~names =
Worker.local_collect_certs LegacyRootCert ~__context names
Expand Down
22 changes: 22 additions & 0 deletions ocaml/xapi/xapi_pool.ml
Original file line number Diff line number Diff line change
Expand Up @@ -1871,6 +1871,28 @@ let join_common ~__context ~master_address ~master_username ~master_password
Client.Pool.exchange_certificates_on_join ~rpc:unverified_rpc
~session_id ~uuid:my_uuid ~certificate:my_certificate
in
(* Verify the master included its own certificate in the pool bundle
before importing. If it is absent the verified connection in Phase 2
will fail with an opaque Stunnel_verify_error. The filename convention
is "<uuid>.pem" (see Cert_distrib.HostPoolProvider). *)
let master_uuid =
Client.Host.get_uuid ~rpc:unverified_rpc ~session_id
~self:(get_master ~rpc:unverified_rpc ~session_id)
in
let expected_cert_filename = master_uuid ^ ".pem" in
if not (List.mem_assoc expected_cert_filename pool_certs) then (
error
"join_common: master certificate file '%s' is absent from the pool's \
certificate store (/etc/stunnel/certs-pool/). The pool bundle sent \
to the joiner does not contain the master's own certificate. Run \
'xe pool-certificate-sync' on the master and retry."
expected_cert_filename ;
raise
Api_errors.(
Server_error
(pool_joining_master_certificate_not_in_pool_bundle, [master_uuid])
)
) ;
Cert_distrib.import_joining_pool_certs ~__context ~pool_certs
)
(fun () -> Client.Session.logout ~rpc:unverified_rpc ~session_id) ;
Expand Down
Loading