I have an azure worker role deployed which runs a a few scheduled tasks as part of an integration system. I am trying to expose an http endpoint which will provide some administrative functions so I can control aspects of the worker role remotely.
I have the work role and up running the only problem is that I am not able to access http endpoint from the internet.
I have confirmed that the nancy server is running since when I remote onto the VM I am able to connect using the local ip address.
The role config is as follows:
<ServiceDefinition name="Azure" xmlns="http://schemas.microsoft.com/ServiceHosting/2008/10/ServiceDefinition" schemaVersion="2015-04.2.6">
<WorkerRole name="Host.Azure" vmsize="Small">
<ConfigurationSettings>
<Setting name="Microsoft.WindowsAzure.Plugins.Diagnostics.ConnectionString" />
</ConfigurationSettings>
<Startup>
<Task commandLine="mount.cmd" executionContext="limited" taskType="background">
</Task>
</Startup>
<Endpoints>
<InputEndpoint name="http" protocol="http" port="80" localPort="80" />
</Endpoints>
<LocalResources>
</LocalResources>
<Imports>
<Import moduleName="RemoteAccess" />
<Import moduleName="RemoteForwarder" />
</Imports>
</WorkerRole>
</ServiceDefinition>
I am creating the nancy url as follows:
var endpointName = "http";
var instance = RoleEnvironment.CurrentRoleInstance;
var internalEndpoint = instance.InstanceEndpoints[endpointName];
var uri = new Uri($"{internalEndpoint.Protocol}://{internalEndpoint.IPEndpoint}");
return new NancyUri {Value = uri};
Is there something else which I need t o do to get this working?
It had to do with the windows url acl config. I thought because I was supplying the local ip to the nancy host it would work, but I had to add an entry to the http acl in the end.
The nancy url is being built up like this
var uri = new Uri("http://localhost:80");
return new NancyUri {Value = uri};
I setup a task to run the following command
netsh http add urlacl url="http://+:80/" user="Everyone"
Which reference in the csdef file as follows:
<Task commandLine="network.cmd" executionContext="elevated" taskType="background"></Task>
Related
I have an asp.net application hosted on a VM with IIS. Now I would like host the same application in Azure App Services. We had IIS settings modified like Connection Time-out.
How do set Connection Time-out value for Azure App Services
If you want to edit the connectionTimeout setting under system.applicationHost, you could modify the applicationhost.config file. You could create it manually or use IISManager to create the file and modify it.
Here is the sample:
<system.applicationHost>
<sites>
<siteDefaults>
<logFile logFormat="W3C"
directory="%SystemDrive%\inetpub\logs\LogFiles"
enabled="true" />
<traceFailedRequestsLogging enabled="true"
directory="%SystemDrive%\inetpub\logs\FailedReqLogFiles"
maxLogFiles="20" />
<limits connectionTimeout="00:01:00" />
<ftpServer serverAutoStart="true" />
<bindings>
<binding protocol="http" bindingInformation="127.0.0.1:8080:" />
</bindings>
</siteDefaults>
</sites>
</system.applicationHost>
I have a web app running in a Virtual Machine hosted in an Azure Cloud Service. I use Windows. I'm trying to secure the application by installing a SSL certificate.
Here it says that to do so:
"In your development environment, open the service definition file
(CSDEF)"
Development environment? what's that? Eclipse? (I don't use Visual Studio)
This is how this file typically looks like:
<?xml version="1.0" encoding="utf-8"?>
<ServiceDefinition name="CloudService1" xmlns="http://schemas.microsoft.com/ServiceHosting/2008/10/ServiceDefinition">
<WebRole name="WCFServiceWebRole2">
<Endpoints>
<InputEndpoint name="HttpIn" protocol="http" port="80" />
<InputEndpoint name="Https" protocol="https" port="443" certificate="SSL" />
</Endpoints>
<Imports>
<Import moduleName="Diagnostics" />
</Imports>
<Certificates>
<Certificate name="SSL" storeLocation="LocalMachine" storeName="My" />
<Certificate name="MSSecAuth" storeLocation="LocalMachine" storeName="CA" />
<Certificate name="MSInternetAuth" storeLocation="LocalMachine" storeName="CA" />
</Certificates>
<LocalResources>
<LocalStorage name="Logs" cleanOnRoleRecycle="false" sizeInMB="100"/>
</LocalResources>
</WebRole>
</ServiceDefinition>
The question is: Where is the service definition file (CSDEF) located?
If you're running in a Virtual Machine the cloud service definition doesn't apply to you. This is used for deployments to Web or Worker Roles and is normally created when you add an 'Azure Cloud Service' project to a Visual Studio solution.
If you want to protect your VM-based service using SSL you would do this as you would on-premise and ensure that you open port 443 as an endpoint to the VM (http://azure.microsoft.com/en-us/documentation/articles/virtual-machines-set-up-endpoints/).
I have a cloud service which was running fine for a while after upgrading to Azure 2.0 SDK. It has now mysteriously stopped working. I am getting this in the Azure machines event log.
The application '/' belonging to site '19369254' has an invalid
AppPoolId 'ddcc23fe-8eee-4412-a4dd-56b50e18d9f2' set.
Therefore, the application will be ignored.
Followed by :
Site 19369254 was disabled because the root application defined for the site is
invalid. See the previous event log message for information about why the
root application is invalid.
and :
A process serving application pool 'ddcc23fe-8eee-4412-a4dd-56b50e18d9f2'
terminated unexpectedly. The process id was '3696'.
The process exit code was '0x103'.
My service definition:
<?xml version="1.0" encoding="utf-8"?>
<ServiceDefinition name="SMEEDI.Cloud" xmlns="http://schemas.microsoft.com/ServiceHosting/2008/10/ServiceDefinition" schemaVersion="2013-03.2.0">
<WebRole name="SMEEDI.Portal" enableNativeCodeExecution="true">
<Startup>
<Task commandLine="startup.cmd" executionContext="elevated" taskType="simple"></Task>
</Startup>
<ConfigurationSettings>
<Setting name="DiagnosticsConnectionString" />
<Setting name="DataConnectionString" />
<Setting name="BaseUrl" />
<Setting name="DatabaseConnectionString" />
<Setting name="Environment" />
</ConfigurationSettings>
<Sites>
<Site name="Smeedi_WebRole" physicalDirectory="..\..\..\SMEEDI.Portal">
<Bindings>
<Binding name="HttpIn" endpointName="HttpIn" />
</Bindings>
</Site>
</Sites>
<Endpoints>
<InputEndpoint name="HttpIn" protocol="http" port="80" />
</Endpoints>
<Imports>
<Import moduleName="RemoteAccess" />
<Import moduleName="RemoteForwarder" />
</Imports>
</WebRole>
</ServiceDefinition>
How could this suddenly stop working?
What is wrong with the service definition?
The error you are receiving should have nothing to do with the CSDEF file. It appears to be an issue with the configuration of IIS on the Azure instance.
You can try to reimage the instance from the Azure portal or log into the instance to do further troubleshooting. If you choose to remote in, I would examine the IIS configuration, specifically the Application Pools and virtual directories, especially the path since you are changing it in the CSDEF.
Azure should take care of that configuration on its own, which is why reimage or delete and redeploy may be a better first step.
Overview
So I've been jumping through flaming hoops to trying to create a Mutual (2-way) SSL connection between a WCF service hosted on a cloud service (using a webrole) and a Salesforce callout. I'm creating a mega question to outline all the steps I've taken and where I am currently stuck.
Process/Progress
1: Set up SSL on Azure Cloud Service (Success)
Created CNAME pointing the SSL domain (service.mydomain.com) to azure production endpoint (service.cloudapp.net)
Uploaded a signed Certificate to Azure
Added Certificate to WebRole and configured a Https Endpoint using certificate
Created WCF web.config binding with Security Mode="Transport"
After doing this 1-way SSL is working correctly
2: Create Client Certificate using with salesforce. This is an unsigned certificate issued by salesforce. You can download it as a .cer (DONE)
3: Install Salesforce Client Certificate using a Start-up Task (see this article) (DONE, but I'm not sure how to confirm it really worked other than the fact that no error was thrown on deployment)
4: Set up WCF to require Client Certificate (DONE, see web.config)
5: Unlock VM IIS webserver/security/access/sslflags using Startup task in WebRole and
Override setting in WCF web.config (DONE, see startup.cmd and web.config)
Apparently with Cloud services the Startup tasks will run before IIS is actually configured on the VM. Because of this I had to implement a hack using ping to delay and running in the background. This actually seems to work as before I was getting a 500 - Configuration Error.
6: Send Client Certificate in SF Request (DONE, see SF code)
Result:
I get a 403.7 - Forbidden error from the server. I believe that it has something to do with the SF Certificate not being trusted by the Service but I can be sure. It's obviously next to impossible to test because of the Cloud to Cloud nature of the system.
UPDATE
So I was able to resolve the 403.7 error by changing the store from 'root' to 'ca'. However now I'm dealing with an inconsistency issue where sometimes the start.cmd seems to work and other times it doesn't seem to take any or only partial effect. If my reboot my service it cycles between 500 errors for the configuration flags being locked by IIS, the 403.7 error mentioned above, and it actually working perfectly.
I found this blog post that uses a custom program (ExecWithRetries.exe) to delay and retry startup tasks until they complete successfully, but I'm still not getting inconsistent results (maybe because appcmd might not throw an error even if it runs before IIS is configured by the VM?).
What my startup.cmd now looks like:
%windir%\System32\inetsrv\appcmd.exe unlock config /section:system.webServer/security/access
REM certutil -addstore -enterprise -f -v root Startup\MagnetClient.cer
certutil -addstore ca Startup\MagnetClient.cer
And the task config like this:
<startup>
<Task commandLine="Startup/ExecWithRetries.exe "/c:AddCert.cmd" /d:60000 /r:20 /rd:5000" executionContext="elevated" taskType="background" />
</startup>
If anyone can has a solution to get consistent result I will award them the bounty.
Code References
WCF web.config
<configuration>
<system.web>
<customErrors mode="Off"></customErrors>
<compilation debug="true" targetFramework="4.0" />
</system.web>
<system.serviceModel>
<services>
<service name="WCFServiceWebRole1.Service1" behaviorConfiguration="metadata" >
<endpoint name="basicHttp"
binding="basicHttpBinding"
bindingConfiguration="https"
contract="WCFServiceWebRole1.IService1" >
</endpoint>
</service>
</services>
<bindings>
<basicHttpBinding>
<binding name="https">
<!-- Step 1 -->
<security mode="Transport">
<!-- step 4 -->
<transport clientCredentialType="Certificate" />
</security>
</binding>
</basicHttpBinding>
</bindings>
<behaviors>
<serviceBehaviors>
<behavior name="metadata">
<serviceMetadata httpsGetEnabled="true" />
<!--<serviceDebug includeExceptionDetailInFaults="true"/>-->
</behavior>
</serviceBehaviors>
</behaviors>
<serviceHostingEnvironment multipleSiteBindingsEnabled="true" />
</system.serviceModel>
<system.webServer>
<httpErrors errorMode="Detailed"/>
<asp scriptErrorSentToBrowser="true" />
<modules runAllManagedModulesForAllRequests="true"/>
<!-- Override iis config mentioned in step 5 -->
<security>
<access sslFlags="SslRequireCert"/>
</security>
</system.webServer>
</configuration>
WebRole Service Definitions
<ServiceDefinition name="WindowsAzureProject1" xmlns="http://schemas.microsoft.com/ServiceHosting/2008/10/ServiceDefinition" schemaVersion="2013-03.2.0">
<WebRole name="WCFServiceWebRole1">
<!-- step 3 & 5 -->
<Startup>
<Task commandLine="Startup/startup.cmd" executionContext="elevated" taskType="background">
</Task>
</Startup>
<Sites>
<Site name="Web">
<Bindings>
<Binding name="Endpoint1" endpointName="Endpoint1" />
<Binding name="Endpoint2" endpointName="Endpoint2" />
</Bindings>
</Site>
</Sites>
<Endpoints>
<InputEndpoint name="Endpoint1" protocol="http" port="80" />
<!-- step 1 -->
<InputEndpoint name="Endpoint2" protocol="https" port="443" certificate="example.example.com" />
</Endpoints>
<Imports>
<Import moduleName="Diagnostics" />
</Imports>
<LocalResources>
<LocalStorage name="WCFServiceWebRole1.svclog" sizeInMB="1000" cleanOnRoleRecycle="false" />
</LocalResources>
<Certificates>
<!-- Step 1 -->
<Certificate name="example.example.com" storeLocation="LocalMachine" storeName="My" />
<Certificate name="Go Daddy Secure Certification Authority" storeLocation="LocalMachine" storeName="Trust" />
<Certificate name="Go Daddy Class 2 Certification Authority" storeLocation="LocalMachine" storeName="Trust" />
</Certificates>
<ConfigurationSettings>
</ConfigurationSettings>
</WebRole>
</ServiceDefinition>
startup.cmd
REM *HACK to wait a ridiculously long time until we can be
REM *pretty sure the VM has initialized IIS
ping -n 600 127.0.0.1 nul
%windir%\System32\inetsrv\appcmd.exe unlock config /section:system.webServer/security/access
REM add SF client certy to root store
certutil -addstore -enterprise -f -v root Statup\ClientCert.cer
Sales Force Example Code
string b = '';
b = b + '<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/"><s:Body>';
b = b + '<TestService xmlns="http://tempuri.org/">';
b = b + '<echoString>test Message</echoString>';
b = b + '</TestService></s:Body></s:Envelope>';
Http h = new Http();
HttpRequest req = new HttpRequest();
//this should add the certificate created by salesforce
req.setClientCertificateName('MyClientCert');
req.setMethod('POST');
req.setEndpoint('https://service.mydomain.com/service1.svc');
req.setHeader('Content-type','text/xml');
req.setHeader('SoapAction', 'http://tempuri.org/IService1/TestService');
req.setBody( b );
HttpResponse res = h.send(req);
string m = res.getbody();
System.Debug(m);
I'll offer a couple suggestions:
Enable RemoteAccess to your azure deployment and redeploy. Then login and MMC to the Cert store to see if the SalesForce client cert actually got installed.
Add <Runtime executionContext="elevated" /> right after <WebRole name="WCFServiceWebRole1"> in your service configuration (see my answer to this SO Post) to ensure the worker process has access to the cert store.
NOTE: A reliable way to delay is to use the CHOICE command:
:: Delay for 60 seconds
%windir%\System32\choice.exe /D Y /T 60 > NUL:
To capture the output of commands redirect the error and standard output to a file you can get to:
certutil -addstore ca Startup\sfdc-client.cert.cer 2>&1 >> %temp%\AddCerts.out
the 2> tells the console to capture the "ERROUT" handle
the &1 binds that output to the STDOUT handle
the >> appends the STDOUT handle to a file
I'm hosting web site and web service in same Web Role using Windows Azure. The problem is that for each site/application there is created a separate application pool on IIS.
Is there any way to make all of them share one application pool?
Here is my actual csdef for which I have three different application pools in IIS (1x for Virtual Application, 1x for site AppWS and 1x for site Web)
<WebRole name="Orchard.Azure.Web" vmsize="ExtraSmall">
<Sites>
<Site name="Web">
<VirtualApplication name="VAppWS" physicalDirectory="..\..\..\AppWS" />
<Bindings>
<Binding name="Binding80" endpointName="Endpoint80" />
<Binding name="Binding443" endpointName="Endpoint443" />
</Bindings>
</Site>
<Site name="AppWS" physicalDirectory="..\..\..\AppWS">
<Bindings>
<Binding name="Binding444" endpointName="Endpoint444" />
</Bindings>
</Site>
</Sites>
<Endpoints>
<InputEndpoint name="Endpoint80" protocol="http" port="80" />
<InputEndpoint name="Endpoint443" protocol="https" port="443" certificate="ssl.root" />
<InputEndpoint name="Endpoint444" protocol="https" port="444" certificate="ssl.ws" />
</Endpoints>
...
I don't know any way to specify the apppool, so you have to run some code after IISConfigurator has done its job and reassign appools.
You could use Azure startup task, but unfortunately it runs too early - before IISconfigurator.
Take a look at this for a workaround: http://mvolo.com/configure-iis-websites-windows-azure-startup-tasks-appcmd/
He creates a special async task that runs the init commands after IISConfigurator.
The init commands could be something like this - it assigns all app pools to a newly created one:
%windir%\system32\inetsrv\appcmd add apppool /name:MyApplicationPool /managedRuntimeVersion:v4.0
%windir%\system32\inetsrv\appcmd list app /xml | %windir%\system32\inetsrv\appcmd set app /in /applicationPool:MyApplicationPool
Another approach could be to do the reassigning in a special webapp using Microsoft.Web.Administration assembly.
Take a look at this for an example: http://www.wadewegner.com/2011/01/programmatically-changing-the-apppool-identity-in-a-windows-azure-web-role/