I need to authenticate requests to Azure Cloud Service Web Role using client certificates. How to put the Certification Authority (CA) root certificate in a right trusted store?
I tried to upload it in Management Portal and then defining it in service definition file with AuthRoot store name:
<Certificate name="RootCA" storeLocation="LocalMachine" storeName="AuthRoot" />
What's really strange is that it works... but only sometimes. It may work after an instance reboot, but may not work after a service update or another instance reboot. It seems like a bug in Azure.
When I say "works" I mean server successfully accepts the client certificate and processes the request.
When I say "doesn't work" I mean server doesn't negotiate a connection after certificate checks and "The request was aborted: Could not create SSL/TLS secure channel." exception is thrown on a client side.
How to make it working stable?
UPD:
Found this record in System Windows Event Log (source is Schannel):
When asking for client authentication, this server sends a list of
trusted certificate authorities to the client. The client uses this
list to choose a client certificate that is trusted by the server.
Currently, this server trusts so many certificate authorities that the
list has grown too long. This list has thus been truncated. The
administrator of this machine should review the certificate
authorities trusted for client authentication and remove those that do
not really need to be trusted.
The exact problem is described here: http://support.microsoft.com/kb/2801679.
After December 2012 Windows update a lot of certificates were added to AuthRoot store. So we have to remove them to solve the problem.
To make it I use PowerShell startup task:
Get-ChildItem -Path Registry::HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\SystemCertificates\AuthRoot\Certificates | Where-Object {$_.Name -notlike "*\<YOUR_CERTIFICATE_THUMBPRINT>"} | Remove-Item
To run it from CMD startup task:
PowerShell -ExecutionPolicy Unrestricted .\Startup.ps1
exit /b %errorlevel%
And in ServiceDefinition.csdef:
<WebRole name="Web">
<Startup>
<Task commandLine="Startup.cmd" executionContext="elevated" taskType="simple" />
</Startup>
<!-- ... ->
</WebRole>
Related
I use the below script to import a certificate in a pipeline build process,
Powershell script:
param($PfxFilePath, $Password)
$absolutePfxFilePath = Resolve-Path -Path $PfxFilePath
Write-Output "Importing store certificate '$absolutePfxFilePath'..."
Add-Type -AssemblyName System.Security
$cert = New-Object System.Security.Cryptography.X509Certificates.X509Certificate2
$cert.Import($absolutePfxFilePath, $Password, [System.Security.Cryptography.X509Certificates.X509KeyStorageFlags]"PersistKeySet")
$store = new-object system.security.cryptography.X509Certificates.X509Store -argumentlist "MY", CurrentUser
$store.Open([System.Security.Cryptography.X509Certificates.OpenFlags]::"ReadWrite")
$store.Add($cert)
$store.Close()
Get below error:
. 'C:\JobAppAgent_work\1\s\JobApp\DevOps\Build\Import-PfxCertificate.ps1' -PfxFilePath $env:DOWNLOADSECUREFILE1_SECUREFILEPATH -Password ****
Importing store certificate 'C:\JobAppAgent_work_temp\DD.Job.Desktop_TemporaryKey.pfx'...
##[error]Exception calling "Import" with "3" argument(s): "The specified network password is not correct.
This script was running fine when build was running on Azrure PipeLines. Now I create a private Agent pool that runs on a Window 10 VM.
Make sure that the certificate is valid and has not expired. You can check the expiration date of the certificate by double-clicking on it and viewing the details.
Check that the certificate is properly installed on the machine where the build is being performed. If the certificate is not installed, it will not be available for use in the build process.
Make sure that the certificate is correctly referenced in the build pipeline. This may involve specifying the path to the certificate file or the thumbprint of the certificate.
If you are using a self-signed certificate, make sure that it is trusted by the machine where the build is being performed. To do this, you will need to install the certificate in the trusted root certification authorities store on the machine.
If you are using a certificate from a certificate authority (CA), make sure that the CA is trusted by the machine where the build is being performed. This may involve installing the root certificate of the CA on the machine.
This is a PowerShell script that imports a certificate from a file with a given password into the "MY" store in the current user's certificate store. The certificate is imported using the Import method of the X509Certificate2 class, which takes as input the path to the certificate file, the password, and a set of key storage flags. The script then creates an X509Store object representing the "MY" store in the current user's certificate store, opens the store in read-write mode, adds the imported certificate to the store, and closes the store.
This script assumes that the certificate file is in the Personal Information Exchange (PFX) format, which is a common format for storing certificates and their private keys. PFX files are often used to export or import certificates, and they can be password-protected for added security.
Verify that the password you are using to import the certificate is correct. It's possible that the password has been changed or entered incorrectly.
Check that the certificate file has not been damaged or modified in any way. If the file has been altered, it may be causing the import to fail.
Make sure that the certificate file is accessible to the machine where the script is being run. If the file is on a network share or another machine, check that the machine has the necessary permissions to read the file.
If the certificate file is password-protected, make sure that the password has not expired or been revoked.
Try running the script with different key storage flags to see if that has any effect on the error. For example, you could try using "Exportable" instead of "PersistKeySet" as the key storage flag.
I have a WCF service that is telling me it can't find its certificate:
Cannot find the X.509 certificate using the following search criteria:
StoreName 'My', StoreLocation 'CurrentUser', FindType
'FindByThumbprint', FindValue
'cf51e92041d0440a262df6a357f3f709f6f8d710'.
and the config specifies the certificate by the thumbprint
<serviceCertificate storeLocation="CurrentUser" storeName="My"
findValue="cf51e92041d0440a262df6a357f3f709f6f8d710"
x509FindType="FindByThumbprint" />
Using the powershell command Get-ChildItem cert:\CurrentUser\My finds the certificate. If I change the config file to specify LocalMachine the service starts correctly.
What is going on? I suppose I could change the config file, however, when publishing my service to Azure then it can't find the uploaded certificate because that is looking in CurrentUser. I know I could use different configs for different environments, but I don't want to blindly head down that path without understanding the "why" of things.
Service Fabric RunAs feature
By default, a Service Fabric application will run with the Network Service account. Microsoft has (partial) documentation on how to run it with other permissions: RunAs: Run a Service Fabric application with different security permissions.
Based on this, here's what I'm trying to do:
My Service Fabric application calls a library that is being developed in an other repository.
When deployed in the cloud, the services will download the binaries for the library from a storage, unzip them in a working directory of the Service Fabric cluster and load it from there.
At development time, when I'm testing or debugging the application in a local cluster, I want the binaries for the library to be loaded from some folder on my local hard drive where I have just compiled them, that is right next to the source code.
The tricky part is that my company's security policies require the source code of said library to be accessible only to authorized users, which translates into the folder containing this code being read-protected. As a consequence my Service Fabric application, which runs as Network Service, can't access my binaries. Changing the security policies is not possible, nor giving Network Service access to the folder.
How can I configure my application so that it runs as a user that would have the correct access rights ?
Here's what I already tried:
Using a domain user
The easiest solution would be to be able to run the Service Fabric application with my own login. I tried this by adding the following to my ApplicationManifest.xml:
<Principals>
<Users>
<User Name="SfUser" AccountName="Domain\UserName" AccountType="DomainUser" Password="pass" />
</Users>
</Principals>
<Policies>
<DefaultRunAsPolicy UserRef="SfUser" />
</Policies>
This works: the application runs as Domain\UserName and can access all the folders I need. But this requires me to put my password in the configuration file, which is not satisfactory.
Using a local user
I then tried using a local user, thinking I would be able to configure access rights correctly using local user groups. The simplest version I could come up with is this:
<Principals>
<Users>
<User Name="SfUser" AccountName="LocalSfUser" AccountType="LocalUser">
<MemberOf>
<SystemGroup Name="MyLocalGroup"/>
</MemberOf>
</User>
</Users>
</Principals>
<Policies>
<DefaultRunAsPolicy UserRef="SfUser" />
</Policies>
I think this configuration is correct since when I deploy my application I can see in Windows user manager that several "technical" users where created by Service Fabric and that they belong to MyLocalGroup. However my application never starts.
I noticed several messages in Windows event viewer that seem related to the problem:
Logon Type: 8
Failure Information:
Failure Reason: The user has not been granted the requested logon type at this machine.
Process Information:
Caller Process Name: C:\Program Files\Microsoft Service Fabric\bin\FabricHost.exe
Apparently, "Logon Type 8" means "Network clear text logon". I suspect a local policy preventing this kind of logon in my company.
When you run as a localuser, this creates a random local user account on the machine. The reason this is most likely failing in the example above is the <SystemGroup Name="MyLocalGroup"/> needs to be a valid Windows system group such as "Administrators". You also do not really need the AccountName attribute above, but it does no harm.
To solve you issue of getting a file from a remote directory you need to use a domain user as you tried since a local user does not have a shared secret that can be verified with AD. The difference is that you can encrypt the password in the application manifest using a certificate that is deployed to the machine. I have put an example ApplicationManifest.xml snippet below, showing how the password for the domain user is encrypted with a certificate called "MyCert".
<Principals>
<Users>
<User Name="TestUser" AccountType="DomainUser" AccountName="Domain\User" Password="[Put Encrypted Password Here" PasswordEncrypted="true" />
</Users>
</Principals>
<Policies>
<DefaultRunAsPolicy UserRef="TestUser" />
<SecurityAccessPolicies>
<SecurityAccessPolicy ResourceRef="MyCert" PrincipalRef="TestUser" GrantRights="Full" ResourceType="Certificate" />
</SecurityAccessPolicies>
</Policies>
As a side note the article here https://azure.microsoft.com/en-us/documentation/articles/service-fabric-application-secret-management show how to create the encrypted password in settings.xml which is also often useful.
Received signed certificate, installed in windows user cert. store with the public key from MQ, but getting MQRC_Q_MGR_NOT_AVAILABLE error?
<add key="sslCertStore" value="*USER"/>
<add key="SslCipherSpec" value="TLS_RSA_WITH_AES_128_CBC_SHA256"/>
What's missing?
EDIT
One more question - where certificates should be placed to be available using
<add key="sslCertStore" value="*SYSTEM"/>
Looking at the comments and question i see you mention
Received signed certificate, installed in windows user cert store with the public key from MQ
and
when SSL is optional on the server it all magically works
From this i believe you are trying to connect a client into your Queue Manager where the client application has it's own certificate. Because you have not specified a certificate for the client to use i don't believe the client is connecting with the (signed) certificate you added to the windows certificate store. This is why it works when the SSL is set to optional but does not work when the SSL is set to required. (Assuming you are talking about the SSLCAUTH attribute on the channel)
From this knowledge center page i believe you need to add the following:
<add key="CertificateLabel" value="certificatelabel"/>
replacing certificatelabel with the label of the certificate you want the client to use.
I am trying to implement client certificate authentication on IIS 8. I have deployed my configuration on a development machine and verified it working as expected there. However after setting up on the server, whenever I navigate to the site and am prompted for the client cert, I select it and immediately get the 403.16 error. The failed requests log gives the error code 2148204809 and message "A certificate chain processed, but terminated in a root certificate which is not trusted by the trust provider."
I have a valid client cert and also a valid CA cert. The CA cert is installed in Trusted Root Authorities on the computer account on both the server and the client machine, and the client cert is installed in the Personal area of the Current User account on the client machine.
The client cert is signed directly by the root CA and as I said, both are valid. There are no other certs in the chain and there are no intermediate certs in the Trusted Root Authorities area.
The IIS configuration has sslFlags = SslNegotiateCert and iisClientCertificateMappingAuthentication is enabled.
The server is not configured to send a CTL and we have SendTrustedIssuerList = 0.
I cannot see why the client cert should not be trusted.
Windows 2012 introduced stricter certificate store validations. According to KB 2795828: Lync Server 2013 Front-End service cannot start in Windows Server 2012, the Trusted Root Certification Authorities (i.e. Root) store can only have certificates that are self-signed. If that store contains non-self-signed certificates, client certificate authentication under IIS returns with a 403.16 error code.
To solve the problem, you have to remove all non-self-signed certificates from the root store. This PowerShell command will identify non-self-signed certificates:
Get-Childitem cert:\LocalMachine\root -Recurse |
Where-Object {$_.Issuer -ne $_.Subject}
In my situation, we moved these non-self-signed certificates into the Intermediate Certification Authorities (i.e. CA) store:
Get-Childitem cert:\LocalMachine\root -Recurse |
Where-Object {$_.Issuer -ne $_.Subject} |
Move-Item -Destination Cert:\LocalMachine\CA
According to KB 2801679: SSL/TLS communication problems after you install KB 931125, you might also have too many trusted certificates.
[T]he maximum size of the trusted certificate authorities list that the Schannel security package supports is 16 kilobytes (KB). Having a large amount of Third-party Root Certication Authorities will go over the 16k limit, and you will experience TLS/SSL communication problems.
The solution in this situation is to remove any certification authority certificates you don't trust, or to stop sending the list of trusted certifiation authorities by setting the HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\#SendTrustedIssuerList registry entry to 0 (the default, if not present, is 1).
If the issue continues to persist after the above steps, restart the machine.
In my case I'd been adding the root cert into the 'current user' certificate store on the server and was getting the 403.16 error.
Adding my root cert to the Trusted Root Authorities store for the local machine resolved the issue.
Follow the steps below on the server running IIS.
For Windows Server 2008 R2:
Right click on the certificate file and select 'Install Certificate'. Click next.
Select 'Place all certificates in the following store' and click 'Browse...'
Check 'Show physical stores'
Expand 'Trusted Root Certification Authorities' and select 'Local Computer'. Click OK.
Click Next/Click Finish.
For Windows Server 2012 R2:
Right click on the certificate file and select 'Install
Certificate'.
Select 'Local Machine'. Click Next.
Select 'Place all certificates in the following store' and click 'Browse...'
Select 'Trusted Root Certification Authorities'. Click OK.
Click Next/Click Finish.
For Windows 7:
Start -> Run -> mmc.exe
File -> 'Add or Remove Snap-ins'. Select 'Certificates', click 'Add >' and select 'Computer account' and then 'Local computer'. Click Finish/OK
Expand Certificates (Local Computer) -> Trusted Root Certification Authorities -> Certificates. Right click on Certificates and select All Tasks -> Import.
Select the certificate file and click next.
Select 'Place all certificates in the following store' and click 'Browse...'
Check 'Show physical stores'
Expand 'Trusted Root Certification Authorities' and select 'Local Computer'. Click OK.
Click Next/Click Finish.
I got this error in IIS Express:
HTTP Error 403.16 - Forbidden
Your client certificate is either not trusted or is invalid.
Looking at the TraceLogFiles I saw the following error:
<RenderingInfo Culture="en-US">
<Opcode>MODULE_SET_RESPONSE_ERROR_STATUS</Opcode>
<Keywords>
<Keyword>RequestNotifications</Keyword>
</Keywords>
<freb:Description Data="Notification">BEGIN_REQUEST</freb:Description>
<freb:Description Data="ErrorCode">A certificate chain processed, but terminated in a root certificate which is not trusted by the trust provider.
(0x800b0109)</freb:Description>
</RenderingInfo>
Turned out when I installed Razer Synapse the installation also put a certificate for chromasdk.io in Trusted Root Certification Authorities under Computer Account -> Local computer. I removed this and then everything worked.
Just sharing my experience with Windows 2019 server and IISExpress in combination with a self-signed certificate. I couldn't get it working with editing the registry and in the end I didn't need to.
The following three steps got me there:
Generate a root certificate for the localmachine cert store with powershell:
$cert = New-SelfSignedCertificate -Type Custom -KeySpec Signature -Subject "CN=TestRootCert" -KeyExportPolicy Exportable -HashAlgorithm sha256 -KeyLength 2048 -CertStoreLocation "Cert:\LocalMachine\My" -KeyUsageProperty Sign -KeyUsage CertSign
Generate a client certificate for the localuser cert store, based on the root cert with powershell:
New-SelfSignedCertificate -Type Custom -Subject "CN=TestChildCert" -Signer $cert -TextExtension #("2.5.29.37={text}1.3.6.1.5.5.7.3.2","2.5.29.17={text}upn=test#local") -KeyUsage DigitalSignature -KeyAlgorithm RSA -KeyLength 2048 -CertStoreLocation "Cert:\CurrentUser\My"
Move the root cert from Personal\Certificates to Trusted Root Certification\Certificates
After this I could select the TestChildCert and it was accepted just fine.