How do to use node-windows with service account? - node.js

I am using node-windows to run my node app as a service. Because I intend to use node-expose-sspi I created a service account with powershell (I checked with Test-ADServiceAccount).
If I run this code
var Service = require('node-windows').Service;
// Create a new service object
var svc = new Service({
name:'project-name',
description: 'node server',
script: 'C:\\server\\server.js'
, allowServiceLogon: true
// ,
// env:{
// name: "NODE_ENV",
// value: "production"
// }
});
// Listen for the "install" event, which indicates the
// process is available as a service.
svc.on('install',function(){
svc.start();
});
// Just in case this file is run twice.
svc.on('alreadyinstalled',function(){
console.log('This service is already installed.');
});
// Listen for the "start" event and let us know when the
// process has actually started working.
svc.on('start',function(){
console.log(svc.name+' started!\nVisit http://127.0.0.1:5000 to see it in action.');
});
// Install the script as a service.
svc.install();
I get the console log 'project-name started...' but the service is not created (I checked with get-process).
If I omit 'allowServiceLogon: true' the service is created.
How do I specify the service account in node-windows?

Syntax
node-windows v1.1.8 seems to be using winsw version 2 so you need to set the options according to this xmlConfigFile.md (don't forget the $-sign).
<serviceaccount>
<domain>YOURDOMAIN</domain>
<user>gmsa_account$</user>
<allowservicelogon>true</allowservicelogon>
</serviceaccount>
Troubleshoot
If the service is not created then it is because the gMSA does not have sufficient permissions for a) the npm folder of node-windows (if you installed this globally this should be C:\Users\username\AppData\Roaming\npm, b) the "entry point" of the npm folder (C:\Users\username) and also the folder where your node app.js is (for instance C:\projects\myserverproject). You need at least write permissions.
Also, the windows-node log file in the daemon folder (C:\projects\myserverproject\daemon) will not be created! This makes troubleshooting harder.
Same goes for the user LocalService, too.
My recommendation
If you omit the allowServiceLogon and the other logon-attributes altogether, the service will be created as LocalSystem. LocalSystem has sufficient permissions. Now you can change LocalSystem to the gMSA in the Windows GUI (search for 'services.msc').
If the gMSA not have sufficient permissions, the service will start but stop immediately. Then you can find the error log in the Event Viewer. The error log will tell you which folders you need to add permissions to.

Related

AWS App Runner health check fails even though appropriate port is exposed

I'm trying to deploy my application to AWS App Runner and even though everything seems okay it still fails to deploy because the health check fails. I'm trying to deploy from a source code repository so AWS builds an image for me. I checked the deploy logs and I can see the appropriate port being EXPOSEd:
10-08-2022 09:59:42 PM [Build] Step 5/5 : EXPOSE 4200
When the application starts I can see that it works properly and listens to connections on port 4200:
10-08-2022 10:02:49 PM [ ready ] on http://localhost:4200
yet I get this from App Runner:
10-08-2022 10:07:57 PM [AppRunner] Health check on port '4200' failed. Service is rolling back. Check your configured port number. For more information, read the application logs.
What am I doing wrong? I configured App Runner from the UI using the following parameters:
Source
Source code repository
Deployment Settings
Automatic
Build Settings
Runtime: Node 16
Build command: script/ci (this runs an npm install)
Start command: script/run (this just starts the node app)
Port: 4200
Auto Scaling
Default
Health Check
Default (I tried various settings without success)
Security
Use an AWS-owned key (no Instance role)
Networking
Public access
Observability
none
Tags
none
Possible Culprits
Maybe the protocol is wrong? It mentions a TCP health check but I serve an HTTP API
Maybe I need to set up a custom VPC instead of "Public access"? I tried the default VPC but it didn't work either
Make sure that you have a health check endpoint that returns 200 OK. Next will return 304s in many cases that will mess with your health check. App Runner can't be configured unfortunately for a specific HTTP response code so you can do something like:
import { NextApiRequest, NextApiResponse } from "next";
const handler = (req: NextApiRequest, res: NextApiResponse) => {
res.status(200).json({ ok: Date.now().toString() });
};
export default handler;
Note that a new Date is returned each time so you'll get 200s instead of 304 NotModified.

WinSCP fails to run as a WebJob on Azure App Service

I've developed a .Net console application to run as a webjob under Azure App Service.
This console app is using WinSCP to transfer files from App Service Filesystem to an on-prem FTP Server.
The connectivity between App Service & the on-perm FTP server is Okay.
Most of the time the job succeeds ,the files are synced, and log files written as well.
Sometimes, the job fails, no files synced, and no Log is NOT being written as well.
The Exception that is being fired intermittently on ALL of our Azure environments (Dev, Test, Prod):
WinSCP process terminated with exit code -1073741819 (C0000005). There was no output. Response log file D:\local\Temp\wscp550C.03E988EE.tmp was not created. This could indicate lack of write permissions to the log folder or problems starting WinSCP itself.
Any Clues ?
My code snippet ..
///Session Options
var sessionOptions = new SessionOptions
{
Protocol = Protocol.Sftp,
HostName = host,
UserName = userName,
Password = password,
SshHostKeyFingerprint = sshHostKeyFingerprint
};
///Opening Session & Sync Files
using (var session = new Session())
{
var timestmp = DateTime.Now.ToString("MMddyyyyHHmmss") + ".txt";
session.SessionLogPath = ConfigurationManager.AppSettings["SessionLogPath"] + timestmp;
session.XmlLogPath = ConfigurationManager.AppSettings["XmlLogPath"] + timestmp;
session.XmlLogPreserve = true;
session.FileTransferred += FileTransferred;
session.Open(sessionOptions);
var syncResult = session.SynchronizeDirectories(SynchronizationMode.Remote, localFolder, remoteFolder, false,false);
syncResult.Check();
}
WinSCP process terminated with exit code -1073741819 (C0000005). There was no output. Response log file D:\local\Temp\wscp550C.03E988EE.tmp was not created. This could indicate lack of write permissions to the log folder or problems starting WinSCP itself.
The error messages shows that you don’t give an write permission on production. Please give all write permission in Production Environment.
WinSCP could not create/write to log file that it uses to report back to the .NET assembly . Make sure your process has write permissions to the temporary folder. Alternatively, you can use (undocumented) property Session.XmlLogPath to change the log file location.
Refer here
C0000005 means "(memory) access violation". That probably indicates that WinSCP has crashed. It might mean a bug in WinSCP. Make sure you have the latest version. Otherwise, you better report this on WinSCP support forum, as software bugs do not really belong to Stack Overflow.

Azure node expressjs app crashes randomly without error

I have built a simple node application with expressjs which applies socket.io.
In order for sockets to communicate in cluster mode on azure the app uses also redis cache from azure as well.
This project has being deployed to azure under a linux web app which it uses docker container.
The problem is that i am facing a random crash of the app after 18 hours to 36 (as i have seen) and when you visit the url you see the nginx error web page.
I had used the following code to detect the error to the logs and i also deployed it to a staging environment on a linux machine i own
process
.on('unhandledRejection', (reason, p) => {
logger.error(reason, 'Unhandled Rejection at Promise', p)
})
.on('uncaughtException', err => {
logger.error(err, 'Uncaught Exception thrown')
process.exit(1)
})
On the staging machine there are no crashes at all.
I am starting to think this is something to do with the docker container on the azure but i have no indication of such thing.
** Important the web app is set to be always active **
Any ideas or suggestions
I had something similar before. In my case, it was because I had no log rotation, so the log file would grow into a unique giant file making it impossible for the server to write to it.

Serilog not working in Service Fabric

I am using Serilog to write to a file and try to get more information about an error that is occurring in my production cluster...
In my local dev cluster the log files are created fine but they are not created in the VM's on my production cluster. I think this may be security related
Has anyone ever had this?
My production cluster has 5 nodes with a Windows 2016 VM on each
Even more strange is that this works on a single node cluster in Azure
public static ILogger ConfigureLogging(string appName, string appVersion)
{
AppDomain.CurrentDomain.ProcessExit += (sender, args) => Log.CloseAndFlush();
var configPackage = FabricRuntime.GetActivationContext().GetConfigurationPackageObject("Config");
var environmentName = configPackage.GetSetting("appSettings", "Inspired.TradingPlatform:EnvironmentName");
var loggerConfiguration = new LoggerConfiguration()
.WriteTo.File(#"D:\SvcFab\applog-" + appName + ".txt", shared: true, rollingInterval: RollingInterval.Day)
.Enrich.WithProperty("AppName", appName)
.Enrich.WithProperty("AppVersion", appVersion)
.Enrich.WithProperty("EnvName", environmentName);
var log = loggerConfiguration.CreateLogger();
log.Information("Starting {AppName} v{AppVersion} application", appName, appVersion);
return Log.Logger = log;
}
Paul
I wouldn't recommend logging into local files in Service Fabric, since your node may be moved to another VM any time and you won't have access to these files. Consider using another sinks which write to external system (database, message bus or logging system like loggly)
It is likely a permission issue. Your service might be trying to log to a folder where it does not have permission.
By default, your services will run under same user as the Fabric.exe process, that run as NetworkService, you can find more information about this on this link.
I would not recommend this approach, because many reasons, a few of them are:
Your services might be moved around the cluster so your files will be incomplete
You have to log on multiple machines to find the logs
The node might be gone with files (Scale up + Down, Failure, Disk error)
Multiple instances on same node trying to access the same file
and so on...
On Service Fabric, the recommended way is to use EventSource(or ETW) + EventFlow + Application Insights. They run smoothly together and bring you many features.
If you want to use stay on Serilog, I would recommend you use Serilog + Application Insights instead, it will give you move flexibility on your monitoring. Take a look at the Application Insights sink for serilog here.
This was actually user error! I was connecting to a different cluster of VMs than the one my service fabric was connected to! Whoops!

IIS Application pool identity

I am attempting to obtain a data feed from yahoo finance. I am doing this with the following code:
System.Net.WebRequest request = System.Net.WebRequest.Create(http://download.finance.yahoo.com/download/quotes.csv?format=sl&ext=.csv&symbols=^ftse,^ftmc,^ftas,^ftt1x,^dJA);
request.UseDefaultCredentials = true;
// set properties of the request
using (System.Net.WebResponse response = request.GetResponse())
{
using (System.IO.StreamReader reader = new System.IO.StreamReader(response.GetResponseStream()))
{
return reader.ReadToEnd();
}
}
I have placed this code into a console application and, using Console.WriteLine on the output I receive the information I require. I have used the 'Run as..' command to execute this using a specific domain account.
When I use this code from within a Page load I receive the following error message "No connection could be made because the target machine actively refused it 76.13.114.90:80".
This seems to suggest that the call is reaching yahoo (is this true?) and that there is something missing.
This would suggest there is an identity difference in the calls between the console application and application pool.
Environment is: Windows Server 2003, IIS 6.0, .net 4.0
"Target machine actively refused it" indicates that the TCP connection itself is not succeeding. This could be due to the fact that the Proxy settings when run under IIS are not the same as those that apply when you run in the console.
You can fix this by setting a WebProxy on your request, that points to the proxy server being used in the environment.
Yes, an active refusal is indication that the target machine is receiving the request and the information in the headers is either incorrect or insufficient to process the request. It is entirely possible that if you had to run this call using a "run as" command in console that the application pool's identity user does not have the appropriate permission or username. You can attempt to change the identity user to this specific domain account to see if that alleviates the problem, but you may have to isolate this particular function into its own application pool in order to protect the rest of the website from having this specification.

Resources