oVirt / ovirt-engine

The oVirt Engine virtualization manager
Other
492 stars 259 forks source link

Fix CA generation as non-root user due to .rnd error #929

Closed BrooklynDewolf closed 3 months ago

BrooklynDewolf commented 3 months ago

Changes introduced with this PR

Are you the owner of the code you are sending in, or do you have permission of the owner?

Yes

Co-authored-by: Jean-Louis Dupond jean-louis@dupond.be Signed-off-by: Brooklyn Dewolf contact@brooklyn.gent

mwperina commented 3 months ago

/ost

didib commented 3 months ago

Sorry, I do not understand the problem this should fix, nor what caused it to surface suddenly. Is it a change in openssl (genpkey or req)?

In theory, moving the 'cd ' outside of the subshell starting in line 88 is significant - affects also e.g. keytool.

didib commented 3 months ago

I think that developer mode did work at least at some point after this code was written (~ 11 years ago, based on the git log). I also searched and found now something I wrote many years ago and never get to actually publishing. Might be useful, so putting in a separate comment.

didib commented 3 months ago

How to use ovirt-engine's CA scripts to run a separate CA

The scripts were not designed to allow this, but do not have too many hard-coded paths either. So it's not hard to make them use a different directory.

To create your own copy

MYCADIR=$HOME/testca MYPKIDIR="${MYCADIR}/pki" MYBINDIR="${MYCADIR}/bin"

FQDN="my-ca-common-name.example.org" AIA="caIssuers;URI:http://${FQDN}:80/ca.crt" CA_SUBJECT="/C=US/O=eng.lab.tlv.redhat.com/CN=${FQDN}.ca" SUBJECT="/C=US/O=eng.lab.tlv.redhat.com/CN=${FQDN}.ca" PKIPASS=topsecret

mkdir -p "${MYCADIR}" "${MYPKIDIR}" "${MYBINDIR}"

cp /usr/share/ovirt-engine/bin/pki- "${MYBINDIR}" sed -i -e "s;^PKIDIR.;PKIDIR="${MYPKIDIR}";" -e "s;^USRDIR.*;USRDIR="${MYCADIR}";" "${MYBINDIR}"/pki-common.sh

cd "${MYPKIDIR}" cp /etc/pki/ovirt-engine/{*cert.template.in,openssl.conf} .

Note that this is usually done by engine-setup, and we might do other replacements in the future. But currently AIA is enough.

for f in cert.template cacert.template; do sed "s#@AIA@#${AIA}#" < "${f}.in" > "${f}"; done

mkdir certs keys private requests

To create your CA there

"${MYBINDIR}"/pki-create-ca.sh --subject="${CA_SUBJECT}" --keystore-password="${PKIPASS}"

To create local key

This creates a temp key, csr, signs it, packs into a pkcs12 archive, and removes the temp key. N is the prefix of used files, DN is the domain name for which we do this:

N=name1; DN=myname1.example.org; "${MYBINDIR}"/pki-enroll-pkcs12.sh --name="${N}" --password="${PKIPASS}" --subject="/C=US/O=eng.lab.tlv.redhat.com/CN=${DN}" --san="DNS:${DN}"

To extract the key to its own file without a password:

N=name1; "${MYBINDIR}"/pki-pkcs12-extract.sh --name="${N}" --passin="${PKIPASS}" --key="${MYPKIDIR}/keys/${N}".key.nopass

To create the key and csr outside of the CA, and sign in the CA

Somewhere:

openssl genrsa -out my-thing.key 2048

openssl req -new -out my-thing.csr -key my-thing.key

Copy the csr to the CA, e.g. if on same machine:

cp my-thing.csr "${MYPKIDIR}"/requests/name2.req

Then, to sign, on the CA machine:

N=name2; DN=myname2.example.org; "${MYBINDIR}"/pki-enroll-request.sh --name=${N} --subject="/C=US/O=myorg.redhat.com/CN=${DN}" --san="DNS:${DN}"

Your generated certs are in $MYPKIDIR/certs , in both cases.

To put everything where [1] expects them

[1] https://access.redhat.com/documentation/en-us/red_hat_virtualization/4.2/html/administration_guide/appe-red_hat_enterprise_virtualization_and_ssl#Replacing_the_Manager_CA_Certificate

cp ca.pem /tmp/3rd-party-ca-cert.pem cp keys/name1.key.nopass /tmp/apache.key cp certs/name1.cer /tmp/apache.cer

didib commented 3 months ago

Considering the reference to RHV 4.2 docs, I suppose I tested it at the time and it worked. No idea about later versions.

dupondje commented 3 months ago

Thanks for the review @didib

The issue only occurs when you run engine-setup as a non-root user.

The openssl req command fails:

28467 execve("/usr/bin/openssl", ["openssl", "req", "-batch", "-config", "/home/build/ovirt//etc/pki/ovirt-engine/cacert.conf", "-new", "-key", "/home/build/ovirt//etc/pki/ovirt-engine/private/ca.pem", "-out", "/home/build/ovirt//etc/pki/ovirt-engine/requests/ca.csr", "-subj", "/"], 0x5a7ca1ba52e0 /* 60 vars */) = 0

Is executed AT_FDCWD (which is not changed by the script), and in that folder openssl tries to find the .rnd file. Which does not exist:

28467 openat(AT_FDCWD, ".rnd", O_RDONLY) = -1 ENOENT (No such file or directory)
28467 write(2, "Can't load .rnd into RNG\n", 25) = 25
28280 <... poll resumed>)               = 1 ([{fd=11, revents=POLLIN}])
28467 write(2, "806B8A4B267F0000:error:12000079:random number generator:RAND_load_file:Cannot open file:crypto/rand/randfile.c:106:Filename=.rnd\n", 129) = 129
28280 read(11, "Can't load .rnd into RNG\n806B8A4B267F0000:error:12000079:random number generator:RAND_load_file:Cannot open file:crypto/rand/randfile.c:106:Filename=.rnd\n", 32768) = 154
28280 poll([{fd=9, events=POLLIN}, {fd=11, events=POLLIN}], 2, -1 <unfinished ...>
28467 brk(0x5633f89d7000)               = 0x5633f89d7000
28467 brk(0x5633f89d6000)               = 0x5633f89d6000
28467 futex(0x7f264befaf90, FUTEX_WAKE_PRIVATE, 2147483647) = 0
28467 getpid()                          = 28467
28467 brk(0x5633f89f7000)               = 0x5633f89f7000
28467 brk(0x5633f89f6000)               = 0x5633f89f6000
28467 getrandom("\xcd\x17\x75\x4b\x6c\x2e\x4c\x51\xb0\x5b\xee\xe8\x0b\x10\xf4\x9e\x9f\x84\x5d\xe5\xd5\x4e\x20\x82\xd9\xba\xff\xcd\xfd\x66\xfc\x81\x4d\x80\xfe\xbc\x9f\x55\x51\x07\x53\x34\x0e\xa8\xaa\x5b\xaa\x26", 48, 0) = 48
28467 getpid()                          = 28467
28467 getpid()                          = 28467
28467 getpid()                          = 28467
28467 getpid()                          = 28467
28467 openat(AT_FDCWD, "/home/build/ovirt//etc/pki/ovirt-engine/requests/ca.csr", O_WRONLY|O_CREAT|O_TRUNC, 0666) = 3
28467 fstat(3, {st_mode=S_IFREG|0644, st_size=0, ...}) = 0
28467 write(3, "-----BEGIN CERTIFICATE REQUEST-----\nMIICRTCCAS0CAQAwADCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMio\nhS5Zr5brDeJry/n/aXzAydItYyI/hjs1ncpWFMh1YiEl8kyY8RKHPAJ9nqHcOasL\nm82txSf/Jp1a7kfPaL9O7RAwOK3gnKLd03yF91R8mphESfmQyoOrSyCa8U4lAsay\n1tBpxbskZw8efGm+xqReEVbfXBQJbmFe1q/PVYrZ6aJmCFU6BanC7L1rms5P8qGn\nTHXcYb0Mc7Xe60CoeZqt63ZQjT2Tq+ahJ3wz0096v/Hqn7xp1G50e8YJLpFEwa2t\nt/jzZA4mR1GUHxT/8EdAZefr\nHLHz9KgB3F84ruc+NGPOG7ksnMFkpW9EpZ5SReeAWd/VcoDIyY+OXPTjqqRYb6Mx\nYnh3ThR2BJNh8yUIpT3m1MnkxkEAX1Ovxr3V//5Dncb9e9I7/SGG+yox5Fk+Xpxu\nHIvydvjmJCr2KIZ+MLLBYWmR+HXvwt1fJla8auchk4PjJ/2sZ8l8f3vUA10clAY6\nHnbtDV/2SDZDBCVPFz/2FkCgsMF0Ct09C+MA0owuFoBprbAZaq6IWG1Y1Ao6m6WP\nZ0QHf3x8abybF47R6T+mYrjbtd7c+p6/AOFOAOq4NyrFqwzdWTReKogsdD1+bFI8\nbXlI7tC4i/fH\n-----END CERTIFICATE REQUEST-----\n", 863) = 863
28467 close(3)  = 0

So it will try to create one, which fails, cause it does not have permissions on the current CWD:

28467 newfstatat(AT_FDCWD, ".rnd", 0x7ffd2481ab10, 0) = -1 ENOENT (No such file or directory)
28467 getpid()                          = 28467
28467 openat(AT_FDCWD, ".rnd", O_WRONLY|O_CREAT, 0600) = -1 EACCES (Permission denied)
28467 openat(AT_FDCWD, ".rnd", O_WRONLY|O_CREAT|O_TRUNC, 0666) = -1 EACCES (Permission denied)
28467 write(2, "Cannot write random bytes:\n", 27) = 27

This can be properly fixed by changing the CWD before running the openssl req command. But it can indeed be changed inside the subshell and just move the openssl req command in the subshell.

didib commented 3 months ago

I do not object to merging.

The purpose is not completely clear. I suggest to document this properly. If it makes sense to fit into the commit message, please do. If it's part of a larger project, perhaps link to a relevant document.

Generally speaking, engine-setup supports only one of:

  1. Developer mode - basically follow README.md (and the older and likely-out-of-date [1]), with the aim of running this on a developer laptop, without interfering with the OS and being able to easily clean up and start from scratch
  2. "Non-developer-mode" ("Production mode"? We do not have a term): Things are done on the live system as installed from RPMs, changing /etc etc. as needed. Undoing this can be done with engine-cleanup, but that's less robust, at least if using buggy development versions. Developers used this mode for development mainly on scratch VMs, and it was less comfortable for debugging engine Java code (for which this was done).

For engine-setup, the condition for deciding what mode you are in is simply based on the UID. If it's root, no question. Otherwise, we ask, and abort if user does not ack. packaging/setup/plugins/ovirt-engine-common/base/core/misc.py .

It seems like you are trying to do something in between. Right? I suspect it will require some more work.

In principle, developer-mode can work also on non-RPM systems - I know of someone in the distant past using it on gentoo.

[1] https://www.ovirt.org/develop/developer-guide/engine/engine-development-environment.html

dupondje commented 3 months ago

@didib : We are creating a docker development container to be able to build/test oVirt on any local machine if it has docker :) That PR will come soon. But just already sending in PR's with issues we've hit during the process.

dupondje commented 3 months ago

No code change, just fix Signed-off-by :)

didib commented 3 months ago

/ost

sandrobonazzola commented 3 months ago

Merging based on previous approvals