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

dotnet dev-certs https no longer creates a folder if one does not exist #58330

Open
Gregory-Ledray opened this issue Oct 9, 2024 · 34 comments
Open
Labels
area-commandlinetools Includes: Command line tools, dotnet-dev-certs, dotnet-user-jwts, and OpenAPI

Comments

@Gregory-Ledray
Copy link

Gregory-Ledray commented Oct 9, 2024

Describe the Bug

dotnet dev-certs https no longer creates a folder if one does not exist

Steps to Reproduce

Previously, running the following code worked:

FROM mcr.microsoft.com/dotnet/sdk:8.0 AS build

RUN dotnet dev-certs https -v -ep /aspnet/https/aspnetapp.pfx -p somepassword

Now, it produces an error:

2.418 [26] An error has occurred while exporting the certificate: System.InvalidOperationException: The directory '/aspnet/https' does not exist.  Choose permissions carefully when creating it.
2.418    at Microsoft.AspNetCore.Certificates.Generation.CertificateManager.EnsureAspNetCoreHttpsDevelopmentCertificate(DateTimeOffset notBefore, DateTimeOffset notAfter, String path, Boolean trust, Boolean includePrivateKey, String password, CertificateKeyExportFormat keyExportFormat, Boolean isInteractive).
2.419 There was an error exporting the HTTPS developer certificate to a file.

Workaround - this works:

FROM mcr.microsoft.com/dotnet/sdk:8.0 AS build

RUN mkdir -p /aspnet/https 

RUN dotnet dev-certs https -v -ep /aspnet/https/aspnetapp.pfx -p somepassword

Other Information

Deployment at Oct 8, 2024 10:12 AM (UTC-5:00) worked
Deployment at Oct 9, 2024 11:21 AM (UTC-5:00) failed

Working output

1227 | Step 5/15 : RUN dotnet dev-certs https -ep /aspnet/https/aspnetapp.pfx -p somepassword
1228 | ---> Running in 040e6bd771d1
1229 | The HTTPS developer certificate was generated successfully.
1230 | Removing intermediate container 040e6bd771d1
1231 | ---> d021e0e54e7b

Failed output

Step 5/15 : RUN dotnet dev-certs https -ep /aspnet/https/aspnetapp.pfx -p somepassword
 ---> Running in 83d22d459576
There was an error exporting the HTTPS developer certificate to a file.
The command '/bin/sh -c dotnet dev-certs https -ep /aspnet/https/aspnetapp.pfx -p somepassword' returned a non-zero code: 3

Output of docker version

N/A happened on both Windows Docker Desktop & in Ubuntu CI build

Output of docker info

N/A happened on both Windows Docker Desktop & in Ubuntu CI build

@Gregory-Ledray Gregory-Ledray added bug This issue describes a behavior which is not expected - a bug. untriaged labels Oct 9, 2024
@mthalman mthalman transferred this issue from dotnet/dotnet-docker Oct 9, 2024
Copy link

I couldn't figure out the best area label to add to this issue. If you have write-permissions please help me learn by adding exactly one area label.

1 similar comment
Copy link

I couldn't figure out the best area label to add to this issue. If you have write-permissions please help me learn by adding exactly one area label.

@MichaelSimons
Copy link
Member

dev-certs is a bundled global tool that comes into dotnet/installer. dev-certs comes from the aspnetcore repo so I am not sure the sdk repo is the best place for this issue...moving.

@MichaelSimons MichaelSimons transferred this issue from dotnet/sdk Oct 9, 2024
@dotnet-issue-labeler dotnet-issue-labeler bot added the area-commandlinetools Includes: Command line tools, dotnet-dev-certs, dotnet-user-jwts, and OpenAPI label Oct 9, 2024
@martincostello
Copy link
Member

martincostello commented Oct 9, 2024

Looks like #57108 changed this area

@martincostello
Copy link
Member

/cc @amcasey

@sironjuh
Copy link

Just commenting on this, that our builds are now failing with this exact same error on GitHub Actions.

@amcasey
Copy link
Member

amcasey commented Oct 14, 2024

That was an intentional change, made to improve security. The reasoning was that, if the tool created a directory, it would have to choose file access permissions on the user's behalf and that maximally conservative settings would break some apps. We decided instead to delegate that decision back to the user.

I'm sorry that you spent a bunch of time debugging this. My personal recommendation is to always pass --verbose to dev-certs - the behavior is hard to reason about otherwise.

@amcasey amcasey removed bug This issue describes a behavior which is not expected - a bug. untriaged labels Oct 14, 2024
@amcasey
Copy link
Member

amcasey commented Oct 14, 2024

If this is common enough and we maintain our position on directory creation, we may want to have special output in this case that doesn't require --verbose.

@tibble49
Copy link

@amcasey is there a suggested method/workaround we should use moving forward? is OP's work around the most ideal?

@amcasey
Copy link
Member

amcasey commented Oct 15, 2024

Yes, the new expected flow is mkdir (optionally with chmod) then dev-certs.

@amcasey
Copy link
Member

amcasey commented Oct 16, 2024

@tibble49, @sironjuh, @cgdallas, @Gregory-Ledray Can you help me understand how we can make the error experience more helpful? Putting aside that it's annoying to have the behavior of a tool suddenly change underneath you (sorry), what was it about the experience that made it unclear how to recover (i.e. by adding an explicit mkdir)? Did you see the verbose output and find it unclear or did you not see that output at all and just hit the generic "export failed" message?

@Gregory-Ledray
Copy link
Author

I don't think it was unclear. It looks like it took me between 6 and 22 minutes to fix the problem. The error 2.418 [26] An error has occurred while exporting the certificate: System.InvalidOperationException: The directory '/aspnet/https' does not exist. Choose permissions carefully when creating it. is very specific and provides enough information to code a fix for the issue without using -v.

I opened an Issue because this is a change in behavior I didn't expect, so I assumed it was a bug.

@cgdallas
Copy link

cgdallas commented Oct 16, 2024

In our case, we were using an out-of-the-box aspnet SPA template via dotnet new react that was trying to generate a developer certificate during the build process and the Node build step is what was failing. However, the error from Node had nothing regarding a missing directory or anything on that front, just that it couldn't create a certificate:

#21 33.69   There was an error exporting the HTTPS developer certificate to a file.
#21 33.72   failed to load config from /src/src/apps/Project.Client/vite.config.ts
#21 33.72   error during build:
#21 33.72 EXEC : error : Could not create certificate. [/src/src/apps/Project.Client/Project.Client.esproj]
#21 33.72       at file:///src/src/apps/Project.Client/vite.config.ts.timestamp-1729011205871-e11e525c33175.mjs:39:11
#21 33.72       at ModuleJob.run (node:internal/modules/esm/module_job:195:25)
#21 33.72       at async ModuleLoader.import (node:internal/modules/esm/loader:337:24)
#21 33.72       at async loadConfigFromBundledFile (file:///src/src/apps/Project.Client/node_modules/vite/dist/node/chunks/dep-9A4-l-43.js:68383:21)
#21 33.72       at async loadConfigFromFile (file:///src/src/apps/Project.Client/node_modules/vite/dist/node/chunks/dep-9A4-l-43.js:68240:28)
#21 33.72       at async resolveConfig (file:///src/src/apps/Project.Client/node_modules/vite/dist/node/chunks/dep-9A4-l-43.js:67841:28)
#21 33.72       at async build (file:///src/src/apps/Project.Client/node_modules/vite/dist/node/chunks/dep-9A4-l-43.js:67013:20)
#21 33.72       at async CAC.<anonymous> (file:///src/src/apps/Project.Client/node_modules/vite/dist/node/cli.js:845:9)
#21 33.74 /root/.nuget/packages/microsoft.visualstudio.javascript.sdk/0.5.126-alpha/Sdk/Sdk.targets(230,5): error MSB3073: The command "npm run build" exited with code 1. [/src/src/apps/Project.Client/Project.Client.esproj]

So I don't know how the dotnet tooling would have been able to surface something since the Node process is the one that ran into the issue. Had we seen an error similar to what Gregory mentioned above, that would have been way more clear as to what happened though - I'm just not sure its feasible.

@amcasey
Copy link
Member

amcasey commented Oct 16, 2024

I opened an Issue because this is a change in behavior I didn't expect, so I assumed it was a bug.

Totally fair point and we appreciate it. 😄 In this case, it happens to have been expected, but keep filing those bugs.

@amcasey
Copy link
Member

amcasey commented Oct 16, 2024

@cgdallas I didn't know there was a SPA template that depended on exporting the dev cert - I'll give that a shot. The template may need to be updated to do the directory creation. It's also possible we can change the error surfaced from node - I think There was an error exporting the HTTPS developer certificate to a file is verbatim from dev-certs.

@amcasey
Copy link
Member

amcasey commented Oct 16, 2024

@cgdallas Can I bug you for repro steps? I did the trivial dotnet new react and dotnet run but didn't hit that error. I'm guessing you're deploying to a container somewhere in there?

amcasey added a commit to amcasey/aspnetcore that referenced this issue Oct 16, 2024
During a recent security review of the dev-certs tool, we observed that on export it would create a directory that was potentially world-readable (e.g. based on permissions inherited from the parent directory).  We decided it would be more appropriate to let users make the decision of who should have access to the directory.  Unfortunately, this removal of functionality broke some app authors' workflows.  When dev-certs is run directly, the `--verbose` output makes it clear what went wrong and what needs to happen, but the non-verbose output that appears when another tool does the export is less helpful.  This change introduces a new top-level error state for an export failure caused by a non-existent target directory to make it clearer how to fix broken workflows.

The behavior changed in dotnet#57108, which included a backport of dotnet#56985, and shipped in 8.0.10.

For dotnet#58330
@cgdallas
Copy link

Hey @amcasey

Correct that we encountered this issue as part of Docker container build being run by a Github Action.

FWIW, I just tried a dotnet new react command from my dev machine and it does not produce the same project structure as the solution that experienced this issue for us. Our solution is a split one - an esproj for the frontend and a csproj for the backend.

So I guess I can't say with 100% certainty how it was created since it predates me. I (incorrectly) assumed it was just a dotnet new react but maybe this was a VS template of some kind? (Or some amalgamation of various online snippets.)

And just for other references, this was the Vite issue where the possibility of my error being a dotnet issue came from:

github-actions bot pushed a commit that referenced this issue Oct 16, 2024
During a recent security review of the dev-certs tool, we observed that on export it would create a directory that was potentially world-readable (e.g. based on permissions inherited from the parent directory).  We decided it would be more appropriate to let users make the decision of who should have access to the directory.  Unfortunately, this removal of functionality broke some app authors' workflows.  When dev-certs is run directly, the `--verbose` output makes it clear what went wrong and what needs to happen, but the non-verbose output that appears when another tool does the export is less helpful.  This change introduces a new top-level error state for an export failure caused by a non-existent target directory to make it clearer how to fix broken workflows.

The behavior changed in #57108, which included a backport of #56985, and shipped in 8.0.10.

For #58330
@amcasey
Copy link
Member

amcasey commented Oct 16, 2024

@cgdallas Thanks! I think that template had to change pretty regularly to stay up-to-date with react. However, I checked our docs and it looks like it may no longer be supported. Nevertheless, I got the info I needed and I've posted a PR (no promises).

@cgdallas
Copy link

Glad to hear it - we ended up fixing up our Vite build process to not run if it's running in the CI pipeline, there didn't seem much point in having dev-certs run for those builds anyways.

github-actions bot pushed a commit that referenced this issue Oct 16, 2024
During a recent security review of the dev-certs tool, we observed that on export it would create a directory that was potentially world-readable (e.g. based on permissions inherited from the parent directory).  We decided it would be more appropriate to let users make the decision of who should have access to the directory.  Unfortunately, this removal of functionality broke some app authors' workflows.  When dev-certs is run directly, the `--verbose` output makes it clear what went wrong and what needs to happen, but the non-verbose output that appears when another tool does the export is less helpful.  This change introduces a new top-level error state for an export failure caused by a non-existent target directory to make it clearer how to fix broken workflows.

The behavior changed in #57108, which included a backport of #56985, and shipped in 8.0.10.

For #58330
wtgodbe pushed a commit that referenced this issue Oct 16, 2024
* Improve dev-certs export error message

During a recent security review of the dev-certs tool, we observed that on export it would create a directory that was potentially world-readable (e.g. based on permissions inherited from the parent directory).  We decided it would be more appropriate to let users make the decision of who should have access to the directory.  Unfortunately, this removal of functionality broke some app authors' workflows.  When dev-certs is run directly, the `--verbose` output makes it clear what went wrong and what needs to happen, but the non-verbose output that appears when another tool does the export is less helpful.  This change introduces a new top-level error state for an export failure caused by a non-existent target directory to make it clearer how to fix broken workflows.

The behavior changed in #57108, which included a backport of #56985, and shipped in 8.0.10.

For #58330

* Improve error test
wtgodbe pushed a commit that referenced this issue Oct 16, 2024
* Improve dev-certs export error message

During a recent security review of the dev-certs tool, we observed that on export it would create a directory that was potentially world-readable (e.g. based on permissions inherited from the parent directory).  We decided it would be more appropriate to let users make the decision of who should have access to the directory.  Unfortunately, this removal of functionality broke some app authors' workflows.  When dev-certs is run directly, the `--verbose` output makes it clear what went wrong and what needs to happen, but the non-verbose output that appears when another tool does the export is less helpful.  This change introduces a new top-level error state for an export failure caused by a non-existent target directory to make it clearer how to fix broken workflows.

The behavior changed in #57108, which included a backport of #56985, and shipped in 8.0.10.

For #58330

* Improve error text

---------

Co-authored-by: Andrew Casey <[email protected]>
@satiyeh
Copy link

satiyeh commented Oct 17, 2024

@amcasey did you also check out this template here? https://learn.microsoft.com/en-us/visualstudio/javascript/tutorial-asp-net-core-with-react?view=vs-2022

This template is the one that splits the project into a Project.Client and Project.Server similar to how @cgdallas described.

@amcasey
Copy link
Member

amcasey commented Oct 18, 2024

Thanks! That does look more similar to what was described above. You need to enable container support to trigger cert export, which makes sense. I'm not sure yet whether the project is doing that or the VS tooling (I'm guessing the latter).

@seangwright
Copy link
Contributor

I have an app that executes and npm build via <Exec Command="npm run build" /> in my .csproj. That npm build runs webpack and ensures the aspnet core dev certs are created on the filesystem for webpack to use so that the webpack dev server serves over https with a trusted certificate.

This dev-certs change caused my builds to start failing and the only output I saw was the message There was an error exporting the HTTPS developer certificate to a file. from MSBuild with error MSB3073.

Thankfully a search brought me here and I also disabled the dev cert creation during CI.

@mderriey
Copy link
Contributor

Thanks for reporting, I stumbled on that issue today, and it would have taken me a while to figure out both using --verbose to get more information, and that the issue came from the fact that the containing directory doesn't exist.

@amcasey
Copy link
Member

amcasey commented Oct 21, 2024

@seangwright @mderriey Thanks for the reports! The next patch should include a better error message.

@amcasey
Copy link
Member

amcasey commented Oct 21, 2024

@amcasey did you also check out this template here? https://learn.microsoft.com/en-us/visualstudio/javascript/tutorial-asp-net-core-with-react?view=vs-2022

This template is the one that splits the project into a Project.Client and Project.Server similar to how @cgdallas described.

The template has already been updated and should have the appropriate mkdir in the next VS 17 patch. (vite.config.js in the client project does an export.) However, it looks like there's a second export somewhere in the VS tooling - I'm still tracking it down. It may not matter if it runs after the template code that exports to the same folder.

amcasey added a commit that referenced this issue Oct 23, 2024
* Improve dev-certs export error message

During a recent security review of the dev-certs tool, we observed that on export it would create a directory that was potentially world-readable (e.g. based on permissions inherited from the parent directory).  We decided it would be more appropriate to let users make the decision of who should have access to the directory.  Unfortunately, this removal of functionality broke some app authors' workflows.  When dev-certs is run directly, the `--verbose` output makes it clear what went wrong and what needs to happen, but the non-verbose output that appears when another tool does the export is less helpful.  This change introduces a new top-level error state for an export failure caused by a non-existent target directory to make it clearer how to fix broken workflows.

The behavior changed in #57108, which included a backport of #56985, and shipped in 8.0.10.

For #58330

* Improve error text

---------

Co-authored-by: Andrew Casey <[email protected]>
@EdCharbeneau
Copy link

I ran into this bug as well. This thread helped me resolve it. Unfortunately, if this is the "new project" experience for someone evaluating .NET, it's not pretty.

@amcasey
Copy link
Member

amcasey commented Oct 24, 2024

@EdCharbeneau Which project template did you use? The React + ASP.NET Core one should be fixed in the next VS 2022 patch and I couldn't find others that appeared to be affected, but please let me know if I missed one.

@EdCharbeneau
Copy link

Yes, it was the ASP + React template.

@amcasey
Copy link
Member

amcasey commented Oct 24, 2024

Well then, I'm sorry for the trouble, but the fix will be available shortly.

@EdCharbeneau
Copy link

Awesome to see this getting fixed quickly!

@langer-jaroslav
Copy link

langer-jaroslav commented Oct 28, 2024

it can be fixed by calling mkdir manually:

const certFilePath = path.join(baseFolder, `${certificateName}.pem`);
const keyFilePath = path.join(baseFolder, `${certificateName}.key`);

console.log(`Certificate path: ${certFilePath}`);

if (!fs.existsSync(certFilePath) || !fs.existsSync(keyFilePath)) {

    // mkdir to fix dotnet dev-certs error 3 https://github.com/dotnet/aspnetcore/issues/58330
    if (!fs.existsSync(baseFolder)) {
        fs.mkdirSync(baseFolder, { recursive: true });
    }
    if (
        0 !==
        child_process.spawnSync(
            "dotnet",
            [
                "dev-certs",
                "https",
                "--export-path",
                certFilePath,
                "--format",
                "Pem",
                "--no-password",
            ],
            { stdio: "inherit" }
        ).status
    ) {
        throw new Error("Could not create certificate.");
    }
}

@Vrajs16
Copy link

Vrajs16 commented Nov 26, 2024

I am wondering why was this working before but then it stopped? Becuase the above code change fixed the issue.

@amranmo1
Copy link

is this reduce capability announced anywhere? seems like its breaking our configuration and need to add extra checking

@martincostello
Copy link
Member

See aspnet/Announcements#515

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
area-commandlinetools Includes: Command line tools, dotnet-dev-certs, dotnet-user-jwts, and OpenAPI
Projects
None yet
Development

No branches or pull requests