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/).
Related
I am able to implement a connected service in a console app via the service reference option in VS using a wsdl. The following configuration changes are required in the app.config for the service to work:
<system.serviceModel>
<bindings>
<customBinding>
<binding name="......">
<security enableUnsecuredResponse="true" authenticationMode="MutualCertificate" allowSerializedSigningTokenOnReply="true" includeTimestamp="false" messageSecurityVersion="WSSecurity10WSTrustFebruary2005WSSecureConversationFebruary2005WSSecurityPolicy11BasicSecurityProfile10" requireSignatureConfirmation="false">
<localClientSettings maxClockSkew="00:10:00" detectReplays="false" />
<localServiceSettings maxClockSkew="00:10:00" detectReplays="false" />
<secureConversationBootstrap>
<localClientSettings detectReplays="false" />
<localServiceSettings detectReplays="false" />
</secureConversationBootstrap>
<issuedTokenParameters useStrTransform="true"></issuedTokenParameters>
</security>
<textMessageEncoding messageVersion="Soap11" />
<httpsTransport maxReceivedMessageSize="2147483647" maxBufferSize="2147483647" requireClientCertificate="true">
</httpsTransport>
</binding>
</customBinding>
</bindings>
<client>
<endpoint address="...." binding="...." behaviorConfiguration="....." bindingConfiguration="....." contract="...." name="...." />
</client>
<behaviors>
<endpointBehaviors>
<behavior name="....">
<clientCredentials>
<serviceCertificate>
<defaultCertificate storeLocation="..." storeName="..." findValue="...." x509FindType="FindBySerialNumber" />
<authentication certificateValidationMode="None" revocationMode="NoCheck" />
</serviceCertificate>
</clientCredentials>
</behavior>
</endpointBehaviors>
</behaviors>
</system.serviceModel>
When I using the same wsdl to setup a connected service in an Azure Function via WCF Web Service Reference the result does not an app.config. How do I implement the app.config above in the Azure Function connected service?
You can use the svcutil tool to generate proxy classes and config files and add them to your project to implement calls.
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 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 have upgraded to azure 1.7 and now my build process is broken. I have a script that runs after the build which simply fires cspack as follows.
cspack "C:\Users\MyAppBuild\.hudson\jobs\MyApp Portal Build\workspace\trunk\Portal\SMEEDI.Cloud\ServiceDefinition.csdef"
/role:MyApp.Portal;"C:\Users\MyAppBuild\.hudson\jobs\MyApp Portal Build\workspace\trunk\Portal\Portal\MyApp.Portal\bin"
/sites:"C:\Users\MyAppBuild\.hudson\jobs\MyApp Portal Build\workspace\trunk\Portal\Portal\MyApp.Portal\bin";"MyApp.Portal"
/out:"C:\Users\MyAppBuild\.hudson\jobs\MyApp Portal Build\MyApp.Cloud.cspkg
This is my service definition:
<?xml version="1.0" encoding="utf-8"?>
<ServiceDefinition name="MyApp.Cloud" xmlns="http://schemas.microsoft.com/ServiceHosting/2008/10/ServiceDefinition" schemaVersion="2012-05.1.7">
<WebRole name="MyApp.Portal" enableNativeCodeExecution="true">
<ConfigurationSettings>
<Setting name="DiagnosticsConnectionString" />
<Setting name="DataConnectionString" />
<Setting name="BaseUrl" />
<Setting name="DatabaseConnectionString" />
<Setting name="Environment" />
</ConfigurationSettings>
<Sites>
<Site name="MyApp_WebRole" physicalDirectory="..\Portal\MyApp.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>
I get the error :
Error: CloudServices7 : The physical directories are not valid for role /sites:C
:\Users\MyAppBuild\.hudson\jobs\MyApp Portal Build\workspace\trunk\Portal\Port
al\MyApp.Portal\bin;MyApp.Portal sites, virtual directories, and virtual appli
cations..
What should the physical directory be?
You may need to use relative path rather than absolute path. Please refer here
When upgrading a project that has relative paths in the csdef (as is the case here) to the 1.8 SDK you should see the warning below in the upgrade log about the change in relative path. This specific change was made to better support parallel builds.
The physicalDirectory attribute of the Site element contains a relative path. This path is relative to the directory in which the target Service Definition file resides when packaged. In previous versions this file was located within the root project directory. In this version, by default, this file is located in the project output directory. You may need to update the relative path to reflect the new location of the target Service Definition file.