Different Endpoint Certificates Per Environment in Service Fabric - azure-service-fabric

I have a service fabric application that exposes an SSL endpoint. I would like to use a different certificate based on the environment. I'm trying to do this with parameters in the ApplicationMainfest.xml file in the same way that I specify other things, such as instance counts. However, parameters appear not to be working for this. I'm wondering if this is actually true and if there are certain things that you cannot parameterize. Also, is there any way to specify a different certificate based on the environment?
Here are the relevant pieces from my application manifest:
<Parameter Name="CERTNAME" DefaultValue="MyCert" />
...
<Certificates>
<EndpointCertificate X509FindValue="..." Name="MyCert" />
<EndpointCertificate X509FindValue="..." Name="SVSSL" />
</Certificates>
<Policies>
<EndpointBindingPolicy EndpointRef="ServiceEndpointHttps" CertificateRef="[CERTNAME]" />
</Policies>
On deployment, I get the following error:
Register-ServiceFabricApplicationType : The CertificateRef '[CERTNAME]' in EndpointBindingPolicy is invalid. There is no matching Certificate in the corresponding ApplicationManifest.

Today the certificate value itself is parameterizable but not the Ref. So instead of changing the reference or the name, you would parameterize the X509FindValue and keep the endpointbindingpolicy the same.
As a note, just any time you run into something you want to parameterize but can't figure out how to do it, there are a few options. Consider for example most things in the Service Manifest, like the port that the service listens on (if you have it statically configured). There are some other ways around this:
Create different manifests (service manifests or application manifests) and replacing them when creating the application package for a given environment
Using something during your build/deployment stages (such as the Tokenizer Task in VSTS) to replace a stub value with the actual value given the environment that the package is being crafted for
Move most of the endpoint configuration stuff to settings.xml and replace those values via the normal application parameter/override behavior. This would mean taking on the work of configuring your endpoints yourself, however.

Related

How to avoid hosting restart when deploying Azure Functions with deployment slot?

I configured pipeline to do zero down time deployment for Azure Functions. For that purpose I have following steps:
create slot
deploy to slot
start swap with preview
complete swap
My understanding of this is process is that all restarts should happen only on preview slot (so only JobHost should be restarted) and this should have a place before final swap. However, I noticed on Application Insight that Hosting stopped which result in on 503 code when I was hitting function. Is there away of avoiding this? I'm not sure if it matters but I use Premium plan.
You cannot avoid the restart but you could use a custom warm-up if your function needs it.
The swap operation waits for the warm-up to finish before swapping with the target swap. You configure this in a web.config file, example below:
<system.webServer>
<applicationInitialization>
<add initializationPage="/" hostName="[app hostname]" />
<add initializationPage="/Home/About" hostName="[app hostname]" />
</applicationInitialization>
</system.webServer>
You can also customize the warm-up behavior with one or both of the following app settings:
WEBSITE_SWAP_WARMUP_PING_PATH: The path to ping to warm up your site. Add this app setting by specifying a custom path that begins with a slash as the value. An example is /statuscheck. The default value is /.
WEBSITE_SWAP_WARMUP_PING_STATUSES: Valid HTTP response codes for the warm-up operation. Add this app setting with a comma-separated list of HTTP codes. An example is 200,202 . If the returned status code isn't in the list, the warmup and swap operations are stopped. By default, all response codes are valid.
I was able to achieve zero downtime deployment setting variable WEBSITE_ADD_SITENAME_BINDINGS_IN_APPHOST_CONFIG to 1. For more info you can take a look here. One drwaback of this is slowness on processing requests during deployment.
I also recommend to follow this github issue where is discussion about zer/miniam downtime deployment.

Automate deploy of Machine Key in a shared config IIS

I'm using Azure DevOps to deploy an ASP.NET application to an IIS servers on-prem. The IIS servers are using a shared configuration so they need a custom Machine Key setup.
I can use XML transform to add add the machineKey entry in the Web.Config
<system.web>
<machineKey decryptionKey="{hex-key value}" validationKey="{hex-key value}"/>
</system.web>
but I don't want to have the actual keys in source control so I'll need to replace those values at deploy time. Substitution is easy enough for appsettings and connection strings but how can I substitute values in the System.Web section of the Web.Config?
How can I substitute values in the System.Web section of the
Web.Config?
What about consider to use one extension Replace token? For why I recommend it is because it can achieve the demand that it can only be replaced during the pipeline running.
Also, its usage is very convenient. Just need to specify the prefix and suffix in the task, and then make apply them in to your web.config file.
Then specify the corresponding variables with same name in Variables tab.
Only this, during the pipeline running, the task could find the corresponding token correctly and replace the value into it.
For detailed steps, you could refer to my previous answer for details: Use replace token task.

Where should I add ServicePlacementPreferPrimaryDomainPolicyDescription in code or manifest file?

I have a cluster span regions and I want specify preferred domain. Problem is looking at sample code in https://learn.microsoft.com/en-us/azure/service-fabric/service-fabric-cluster-resource-manager-advanced-placement-rules-placement-policies, I have no idea where serviceDescription comes from. Anyone knows where I should have these code in my service fabric service code base?
Also, isn't there a similar way to specify it in service fabric manifest file instead of code change (Like how people specify frontend/backend placement)?
Thanks,
Use this code to change a service description:
FabricClient fabricClient = new FabricClient();
StatefulServiceDescription serviceDescription = new StatefulServiceDescription();
serviceDescription.PlacementConstraints = "(HasSSD == true && SomeProperty >= 4)";
await fabricClient.ServiceManager.CreateServiceAsync(serviceDescription);
(source here)
According to the XSD, you can define them as xml, similar to placement constraints.
C:\Program Files\Microsoft SDKs\Service Fabric\schemas\ServiceFabricServiceModel.xsd
As per MS Docs, you can certainly configure it per code, like this:
FabricClient fabricClient = new FabricClient();
StatefulServiceDescription serviceDescription = new StatefulServiceDescription();
serviceDescription.PlacementConstraints = "(HasSSD == true && SomeProperty >= 4)";
// add other required servicedescription fields
//...
await fabricClient.ServiceManager.CreateServiceAsync(serviceDescription);
As for your question about where to do this from - depending on your needs, there are a few options:
Write a separate application that gets run as part of CI/CD deployment pipeline (or do it via powershell New-ServiceFabricService)
The problem with this approach is that it's a bit annoying for developers having to run this after each deployment - as such I prefer:
Write a stateless service that gets instantiated by default (i.e. put an entry inside <DefaultServices> within ApplicationManifest.xml). Within this service you can then instantiate/modify placement constraints using FabricClient, policies, metrics - and drive these via application parameters/configuration
Instantiate services lazily via your API gateway. This works particularly well for partitioned/stateful services (e.g. if you partition by tenantid) or where you want to maintain a pool of workers (e.g. partition_id = random_number % pool size), etc.
You can also configure placement constraints declaratively via application parameters. Unfortunately this doesn't seem to work atm for placement policies (and probably not for metrics either).
If your needs are simple, then the declarative approach is probably simplest! As per above link, add a [Stateless1_InstanceCount] parameter in your application manifest file and put this under default services:
<DefaultServices>
<Service Name="Stateless1">
<StatelessService ServiceTypeName="Stateless1Type" InstanceCount="[Stateless1_InstanceCount]">
<SingletonPartition />
<PlacementConstraints>[Stateless1_PlacementConstraints]</PlacementConstraints>
</StatelessService>
</Service>
</DefaultServices>

Octopus Web.config transforms for client endpoint address

I have a web project that has uses two service endpoints located in the Web.config file under the client --> endpoint --> address portion
I have found the following per Octopus Variables section but cannot seem to find any reference of how to address the changes using and actual variable like you normally would
I am using the webui for Octopus which would be
http://{server-name}/app#/projects/{project-name}/variables
variable-substitution-syntax
I attempted assigning the variables like so, but the values never updated
the original entries look like the following
<endpoint address="http://services-test.example.com/test.svc/soap" binding="basicHttpBinding" bindingConfiguration="soap" contract="test.service" name="soap" />
Name Address Instance
Endpoint[A].Address test-service-a.example.com 1
Endpoint[B].Address test-service-b.example.com 2
Is this something that is ever possible using Octopus Variables? (I know it can be done using regular Web.config Transforms, as we are doing that already).
If it is possible what is would the correct replacement value for the
endpoint address
be and how would I accomplish this for multiple different endpoint addresses?
Sounds like you are most of the way there. If it's already working with your Web.config transforms then all you need to do is replace the value IN the transform with the variable replacement token.
For example: Web.Release.Config
<configuration xmlns:xdt="http://schemas.microsoft.com/XML-Document-Transform">
<system.serviceModel>
<client>
<endpoint address="http://#{Server1}/test.svc/soap" name="x1"
xdt:Locator="Match(name)" xdt:Transform="SetAttributes(address)" />
<endpoint address="#{Endpoint2}" name="x2"
xdt:Locator="Match(name)" xdt:Transform="SetAttributes(address)" />
</client>
</system.serviceModel>
</configuration>
Of course there are lots of options here.
For filenames you could stick with default conventions 'Web.Release.config' or go with 'Web.[Environment].config' or go with something custom. We use 'Web.Octopus.Config' so that it wont get picked up by any other process.
More on naming transforms here: https://octopus.com/docs/deploying-applications/configuration-files#Configurationfiles-Namingconfigurationtransformfiles
More on custom transforms (Web.Octopus.com) here: https://octopus.com/docs/deploying-applications/configuration-files#Configurationfiles-AdditionalConfigurationTransforms
For variables, you could define a variable for just the server (name=x1) which is simpler or just put the whole address in a variable with gives Octopus a lot more control (name=x2).
The key part is getting the variable replacement tokens into the config. Octopus runs the variable substitution on config files first, and then runs the transforms. What that means is the first pass will replace the tokens in your Web.Release.Config, and then Octopus will run the transforms against Web.config
Hope that helps.

no-eclipse tomcat env variable equivalent

I can set an environment variable with Eclipse when I click on the Tomcat Server and then Open Launch configuration -> Environment -> Variable, Value. What is no-gui, no-eclipse textual-xml equivalent of this variable setting?
Context Parameters
See: Context Parameters section of The Context Container page.
You can configure named values that will be made visible to the web application as servlet context initialization parameters by nesting <Parameter> elements inside this element. For example, you can create an initialization parameter like this:
<Context ...>
...
<Parameter name="companyName" value="My Company, Incorporated"
override="false"/>
...
</Context>
This is equivalent to the inclusion of the following element in the web application deployment descriptor (/WEB-INF/web.xml):
<context-param>
<param-name>companyName</param-name>
<param-value>My Company, Incorporated</param-value>
</context-param>
but does not require modification of the deployment descriptor to customize this value.
If you're using gnu-linux operating system you can edit the catalina.sh script to export you environment variable. First line of the script (after comments, of course) should be
export variableName=variableValue
The credit is for Lucas that told me how to do.
If you meant arguments passed to the launching of your servlet context, see the Answer by miku.
Environment Entries
If you meant the Environment Entries feature, use <Environment> rather than <Parameter> seen in that other Answer.
Here is an example where I set a flag signaling if I am running the web app for development, testing, acceptance, education, or production.
<?xml version="1.0" encoding="UTF-8"?>
<Context>
<!-- Domain: DEV, TEST, ACPT, ED, PROD -->
<Environment name = "work.basil.example.deployment-mode"
description = "Signals whether to run this web-app with development, testing, acceptance, education, or production settings."
value = "DEV"
type = "java.lang.String"
override = "false"
/>
</Context>
You have your choice of a few places to place such XML. For this example, we would want to externalize the file, keeping it outside the WAR file containing our web-app. By externalizing, we can deploy our WAR to any of the dev, test, acpt, ed, or prod servers without needing special builds or manual editing. So for this purpose I like to use the feature of Tomcat allowing for an XML file named the same as the context. The file is place in the conf folder, in which you create nested folders named after the Tomcat engine and the host. For example, on my development machine that would be my_tomcat_base_folder/conf/Catalina/localhost/example.xml where example is the name of my context, Catalina is the engine name, and localhost is the host name (not using a domain name while in development).
The syntax of the above XML is Tomcat-specific. For use in Servlet-standard places, such as the /WEB-INF/web.xml file, the equivalent as documented in the Servlet 4 spec section 14.4.21 would be:
<env-entry>
<env-entry-name>work.basil.example.deployment-mode</env-entry-name>
<description>Signals whether to run this web-app with development, testing, acceptance, education, or production settings.</description>
<env-entry-value>DEV</env-entry-value>
<env-entry-type>java.lang.String</env-entry-type>
</env-entry>