Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Entra ID as SAML IdP Causes CodeQL to Fail with Self-Signed Certificate Found in Certificate Chain #17082

Open
matross-gh opened this issue Jul 26, 2024 · 8 comments
Labels
question Further information is requested

Comments

@matross-gh
Copy link

Environment

  • GHES 3.13.0 on Azure VM STIGd to 98% (working fine)
  • EntraID SAML setup for GitHub
    NOTE: Tried OIDC however GitHub 3.13.0 goes to the Azure commercial endpoints and not the government ones.
    NOTE: If trying to send GH audit to EventHub, same issue. GH 3.13.0 defaults to commercial endpoints and not government
  • Configured SAML on GH and verify working fine including hydrating additional claims for GH admins and GH users

Expectation

  • CodeQL executes honoring the certificate chain presented by the GitHub server for CodeQL

Problem

  • Self-Signed certificate found in chain:
    image

Additional Comments / Notes

Cross-Reference for some additional context: https://security.stackexchange.com/questions/146132/self-signed-certificate-for-a-idp-initiated-saml-sso

When executing on my Windows 2022 CodeQL Server:

.\openssl s_client -showcerts -connect <your ghes server fqdn>:443

shows the self-signed certificate in the chain:

Server certificate
subject=*****redacted*****, CN=<your ghes server>
issuer=*****redacted***** Pointing to VALID root and in certificate store and verifed *****
---
No client certificate CA names sent
Peer signing digest: *****redacted*****
Peer signature type: *****redacted*****
Server Temp Key: *****redacted*****
---
SSL handshake has read 4630 bytes and written 395 bytes
Verification error: self-signed certificate in certificate chain
---
New, TLSv1.3, Cipher is *****redacted*****
Server public key is *****redacted*****
This TLS version forbids renegotiation.
Compression: NONE
Expansion: NONE
No ALPN negotiated
Early data was not sent
Verify return code: 19 (self-signed certificate in certificate chain)
---
---
Post-Handshake New Session Ticket arrived:
SSL-Session:
    Protocol  : TLSv1.3
    Cipher    : *****redacted*****
    Session-ID:*****redacted*****
    Session-ID-ctx:
    Resumption PSK: *****redacted*****
    PSK identity: None
    PSK identity hint: None
    SRP username: None
    TLS session ticket lifetime hint: 7200 (seconds)
    TLS session ticket:  *****redacted*****

    Start Time:*****redacted*****
    Timeout   : 7200 (sec)
    Verify return code: 19 (self-signed certificate in certificate chain)
    Extended master secret: no
    Max Early Data: 0
---
@matross-gh matross-gh added the question Further information is requested label Jul 26, 2024
@mbg
Copy link
Member

mbg commented Jul 26, 2024

Hi @matross-gh, you need to make sure that the root certificate used to sign the self-signed certificate is available to Node on the runner. See this discussion for advice on how to do that.

@matross-gh
Copy link
Author

@mbg, I am not sure if I follow you, sorry!

The self-signed certificate in the chain is from Microsoft Azure Federated SSO Certificate during the setup of an Azure Enterprise App. It generates a certificate issued by Microsoft Azure Federated SSO Certificate to Microsoft Azure Federated SSO Certificate for SAML with GitHub.

I have converted it to .pem and setup the environment variable for Node:

NODE_EXTRA_CA_CERTS=d:\certificates\cacert.pem

When I launch node I issue process.env and can "see" NODE_EXTRA_CA_CERTS there.

I have installed that self-signed certificate to my CodeQL server certificate store. This is a Windows 2022 server.

@mbg
Copy link
Member

mbg commented Jul 31, 2024

I have converted it to .pem and setup the environment variable for Node:

Just to clarify, it sounds like you converted the self-signed certificate that is used by GHES and added it there? If so, that isn't right -- you need to take the certificate that was used to sign the certificate used by GHES and make it available to Node.

The error you are getting suggests that, when the CodeQL Action is trying to connect to the API exposed by your GHES instance, it is presented with a TLS certificate that cannot be validated using any of the root certificates available to the Node runtime on the Actions runner. Therefore, it gets flagged as a self-signed certificate and rejected. I would think that this is a general issue with your Actions setup and other Actions which make use of the API would report similar errors.

Here are some more instructions for how to configure things in general: actions/checkout#362 (comment)

However, note that you have opened this issue on the codeql repository. We can help with CodeQL-specific issues and will generally try to help with related issues if we can, but we are not experts on Azure or the particular setup that you are describing about how the certificate is issued. The issue you are describing is broadly an incorrect configuration of your GitHub Actions setup, but may also be a wider issue with your GHES configuration.

@matross-gh
Copy link
Author

@mbg Tried all those options.. that did not work. Also, actions/checkout#362 is back in 2020. Maybe updates/changes introduced or re-introduced things? Who knows...

When I looked at the cert I am giving Node and my runner it IS the full chain.

Something else is going on here... I did follow all GH documentation for this setup.

Thanks for the time..

@matross-gh
Copy link
Author

Additional Update

Logged onto my Windows runner with CodeQL and fired up Node. Small code to see if Node has access to the certificate GHES API is using/after:

  1. Opened PowerShell v7.4.4
  2. Navigated to \actions-runner\externals\node20\bin
  3. Launched Node with .\node
  4. Issued code: (used from: https://stackoverflow.com/questions/68896243/how-to-properly-configure-node-js-to-use-self-signed-root-certificates#:~:text=I%20tried%20to%20use%20the%20NODE_EXTRA_CA_CERTS%3DpathToMycert.pem,info%20to%20know%20what%27s%20going%20on.&text=I%20tried%20to%20use,know%20what%27s%20going%20on.&text=to%20use%20the%20NODE_EXTRA_CA_CERTS%3DpathToMycert.pem,info%20to%20know%20what%27s)
const tls = require('tls');
const fs = require('fs');

const ca = await fs.readFileSync(process.env.NODE_EXTRA_CA_CERTS, 'utf8');
console.log(ca); //successfully print the CA, so it exists.
const inList = tls.rootCertificates.some( cert =>{
    console.log('testing ca : \n',cert);
    return cert == ca;
});
console.log(`CA is ${ !inList ? 'not' : '' } in rootCertificates list...`);

At the end here, I don't get a match. What is interesting is the certificate is definitly found and loaded up in Node. I copied the output from console.log(ca); and it was the chain I have been trying to get Node or CodeQL to "know" about.

HTH

@mbg
Copy link
Member

mbg commented Jul 31, 2024

My understanding is that tls.rootCertificates is a static list that is the same everywhere and not affected by NODE_EXTRA_CA_CERTS. So it's not surprising that this doesn't contain your certificate.

If process.env.NODE_EXTRA_CA_CERTS has the value you expect, then things to check are:

  • Have you restarted the runner since changing NODE_EXTRA_CA_CERTS? I.e. are you sure that the change has propagated and it is actually set for your Actions workflows? You can test this with a step that outputs NODE_EXTRA_CA_CERTS in a workflow, but just restarting the runner is probably easier.
  • If NODE_EXTRA_CA_CERTS in the workflow is definitely correct, then maybe the certificate is wrong. As I said, it needs to be the certificate that was used to sign the self-signed certificate that is used by the GHES API.
  • You could test whether it is the correct certificate manually as well with something like described in this SO answer. If you load the certificate manually, add it to the CA list, make a request to the API, and it still doesn't work, then that suggests it's the wrong certificate.

@matross-gh
Copy link
Author

matross-gh commented Jul 31, 2024

@mbg

yes, process.env.node_extra_ca_certs havs the path I set. I verified with that code it has the cert with the chain.

I restarted the server; everything still checks outs. Also, ran a simple workflow and outputted all environment variables and I can see the node_extra_ca_certs there...

Last thing I can do, then I am done because I am out of options, is to get a new certificate such that the CN of the certificate is not the name of the host.

Will status here how that goes...

@matross-gh
Copy link
Author

@mbg Ok, got a new cert and the CN is not the computer name. CodeQL fails with:

image

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
question Further information is requested
Projects
None yet
Development

No branches or pull requests

2 participants