Announcement: dotnet monitor will require authentication
See original GitHub issuedotnet-monitor has been updated in preview4
to require authentication in the default configuration to access the following endpoints:
/processes
/dump/{pid?}
/gcdump/{pid?}
/trace/{pid?}
/logs/{pid?}
The /metrics
endpoint will still be available without authentication on a separately configured metricsUrl
.
To protect the API keys sent over the wire as part of authentication, dotnet-monitor
will also default to requiring that the underlying channel uses HTTPS.
How to configure dotnet-monitor
for authentication?
Step 1: Generate an SSL certificate
To configure dotnet-monitor
to run securely, you will need to generate an SSL certificate with an EKU for server usage. You can either request this certificate from your certificate authority or generate a self-signed certificate.
If you are running on a development machine with the .NET SDK installed, dotnet-monitor
will default to using the ASP.NET Core HTTPS development certificate. If you wish to generate another self-signed certificate for use on another machine you may do so by invoking the dotnet dev-certs
tool.
dotnet dev-certs https -export-path self-signed-certificate.pfx -p <your-password>
Step 2: Pick an authentication scheme
dotnet-monitor
supports both Windows Authentication (Negotiate) and API token-based authentication. Authenticating requests ensure that lower privileged processes aren’t allow to use this API to exfiltrate sensitive diagnostic artifacts that you haven’t explicitly granted access to.
We recommend using Windows Authentication if you’re running dotnet-monitor
as a local development tool on a Windows machine. For all other environments, we recommend using API token authentication.
Windows authentication doesn’t require explicit configuration. When available dotnet-monitor
will authorize any user authenticated as the same user that started the dotnet-monitor
process. You can skip the remaining steps if you’re using Windows authentication
Step 3: Generate an API token and hashed API token
You need to create a 32-bit cryptographically random secret for use as an API token
$rng = New-Object System.Security.Cryptography.RNGCryptoServiceProvider
$secret = [byte[]]::new(32)
$rng.GetBytes($secret)
$API_TOKEN = [Convert]::ToBase64String($secret)
"Authorization: Bearer $API_TOKEN"
$secretStream = [System.IO.MemoryStream]::new($secret)
$HASHED_TOKEN = (Get-FileHash -Algorithm SHA256 -InputStream $secretStream).Hash
$rng.Dispose()
Write-Output "ApiKeyHash: $HASHED_TOKEN"
Write-Output "ApiKeyHashType: SHA256"
OR
API_TOKEN=`openssl rand -base64 32`
echo "Authorization: MonitorApiKey $API_TOKEN"
HASHED_TOKEN=`$API_TOKEN | base64 -d | sha256sum`
echo "ApiKeyHash: $HASHED_TOKEN"
echo "ApiKeyHashType: SHA256"
OR
>dotnet monitor generatekey
NOTE: The generated API token should be secured at rest. We recommend using a tool such as a password manager to save it.
Step 4: Save these settings
If you’re running on Windows, you can save these settings to %USERPROFILE%\.dotnet-monitor\settings.json
. If you’re on other operating systems, you can save this file to $XDG_CONFIG_HOME/dotnet-monitor/settings.json
.
NOTE: If
$XDG_CONFIG_HOME
isn’t defined, dotnet-monitor will fall back to looking at$HOME/.config/dotnet-monitor/settings.json
{
"ApiAuthentication": {
"ApiKeyHash": "<HASHED-TOKEN>",
"ApiKeyHashType": "SHA256"
},
"Kestrel": {
"Certificates": {
"Default":{
"Path": "<path-to-cert.pfx>",
"Password": "<your-cert-password>"
}
}
}
}
Alternatively, you can use environment variables to specify the configuration
DotnetMonitor_ApiAuthentication__ApiKeyHash="<HASHED-TOKEN>"
DotnetMonitor_ApiAuthentication__ApiKeyHashType="SHA256"
DotnetMonitor_Kestrel__Certificates__Default__Password="<your-cert-password"
DotnetMonitor_Kestrel__Certificates__Default__Path="<path-to-cert.pfx>"
NOTE: If you’re using environment variables to configure the API Key hash, you will not be able to the API Key without restarting the process
If you’re running in Kubernetes, we recommend creating secrets and mounting them into container via a deployment manifest
Creating secrets:
kubectl create secret generic customcert \
--from-file=customcert.pfx=<path-to-certificate> \
--from-literal=pass=<your-cert-password> \
--dry-run=client -o yaml \
| kubectl apply -f -
kubectl create secret generic apikey \
--from-literal=ApiAuthentication__ApiKeyHash=$hash \
--dry-run=client -o yaml \
| kubectl apply -f -
Deployment manifest:
apiVersion: apps/v1
kind: Deployment
metadata:
name: dotnetmonitorsample
labels:
app: dotnetmonitorsample
spec:
replicas: 1
selector:
matchLabels:
app: dotnetmonitorsample
template:
metadata:
labels:
app: dotnetmonitorsample
spec:
volumes:
- name: sharedtmp
emptyDir: {}
- name: apikey
secret:
secretName: apikey
- name: customcert
secret:
secretName: customcert
containers:
- name: dotnetmonitorsample
imagePullPolicy: Always
image: mcr.microsoft.com/dotnet/samples:aspnetapp
resources:
limits:
memory: "256Mi"
cpu: "500m"
volumeMounts:
- name: sharedtmp
mountPath: /tmp
- name: dotnetmonitoragent
env:
- name: ASPNETCORE_Kestrel__Certificates__Default__Password
valueFrom:
secretKeyRef:
name: customcert
key: pass
- name: ASPNETCORE_Kestrel__Certificates__Default__Path
value: /etc/aspnet/customcert/customcert.pfx
image: mcr.microsoft.com/dotnet/nightly/monitor:5.0.0-preview.4
imagePullPolicy: Always
ports:
- containerPort: 52325
resources:
requests:
memory: "64Mi"
cpu: "250m"
limits:
memory: "128Mi"
cpu: "500m"
volumeMounts:
- name: sharedtmp
mountPath: /tmp
- name: customcert
mountPath: /etc/aspnet/customcert
- name: apikey
mountPath: /etc/dotnet-monitor
How to use dotnet-monitor
for authentication?
If running on Windows with Windows authentication, the browser experience will work as it previously did. The browser handle the Windows authentication challenge.
If you using API Token auth, you will need to specify the token via the authorization header
curl.exe -H "Authorization: MonitorApiKey HdFb8OPkE0Dc5hpu0kAxA7hhNguAah9SNUFftlP2Dk0=" https://localhost:52323/processes
OR
curl -H "Authorization: MonitorApiKey HdFb8OPkE0Dc5hpu0kAxA7hhNguAah9SNUFftlP2Dk0=" https://localhost:52323/processes
Issue Analytics
- State:
- Created 3 years ago
- Reactions:1
- Comments:7 (3 by maintainers)
dotnet monitor collect --no-auth
This seems to be planning to use a non-standard scheme,
MonitorApiToken
for theAuthorization
HTTP header. According to the HTTP standard for authentication (RFC7235) the scheme is meant to be one of those registered in IANA’s Hypertext Transfer Protocol (HTTP) Authentication Scheme Registry. (The alternative mechanism you mention,Negotiate
, is registered with IANA. So the problem is just with the novelMonitorApiToken
you’ve proposed.)The first obvious question is: why aren’t you just using
Bearer
? RFC6750 defines this scheme, and the operation of your proposedMonitorApiToken
seems to be a reinvention of the existingBearer
token scheme but by another name.There’s a really good reason for using the existing standard
Bearer
scheme: bearer tokens have certain risks attached to them. Because there’s no proof of ownership mechanism, it’s really important to ensure they are suitably protected. SinceBearer
is a well-defined standard scheme, HTTP infrastructure (proxies, caching, APIs) can be built with a baked-in understanding of the risks, making it possible to impose policies that prevent accidental leaking of data. (E.g., an egress point could detect the use of aBearer
header in an unencrypted request and block it.) But by defining your own non-standard bearer token scheme, you will lose any such protection. This use of a non-standard security scheme introduces security risks, and for no obvious benefit.Second, if you were to attempt to get IANA to register your new scheme, it would almost certainly be rejected because it violates the third bullet point in RFC7235’s ‘Considerations for New Authentication Schemes’. You are in effect using the
token68
production in your header here. This is exactly whatBearer
does, but theBearer
scheme is allowed to get away with this because, as that section of RFC7235 says:I.e.,
Bearer
already worked this way, and it’s regrettable, but too late to change, so the current spec makes a special case for it. But as it says:Your proposed
MonitorApiToken
scheme is definitely “new” so it should use the auth-param syntax defined in RFC7235’s Challenge and Response section.EDIT (by @shirhatti): Created a new issue to track this https://github.com/dotnet/dotnet-monitor/issues/247