Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Guide multi app solution #1085

Merged
merged 46 commits into from
Nov 24, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
46 commits
Select commit Hold shift + click to select a range
0725b08
Add folder for multi-app-solution documentation
standeren Aug 7, 2023
9c20ddd
Add guide for multi-app-solution
standeren Aug 24, 2023
611675a
Fix links and add conditional version demand
standeren Aug 28, 2023
5f5f332
Add testing docs
standeren Aug 28, 2023
5b5160c
Add links to policy
standeren Aug 29, 2023
3b8ea05
Update content/app/guides/multi-app-solution/_index.en.md
standeren Aug 29, 2023
d97dd1a
Update content/app/guides/multi-app-solution/_index.en.md
standeren Sep 14, 2023
9244b77
Update content/app/guides/multi-app-solution/_index.en.md
standeren Sep 14, 2023
3176e9c
Update content/app/guides/multi-app-solution/_index.en.md
standeren Sep 14, 2023
0953669
fix comments from review
standeren Sep 25, 2023
d596d35
added draw.io figure
acn-sbuad Sep 29, 2023
048e535
Change structure
standeren Sep 29, 2023
870b546
Change structure for app a
standeren Oct 12, 2023
9bdd8a2
Update content/app/guides/multi-app-solution/testing/_index.en.md
standeren Oct 19, 2023
f3fc636
Update content/app/guides/maskinporten-app-integration/_index.en.md
standeren Nov 6, 2023
c51eed1
Fix links
standeren Nov 6, 2023
9adb7d8
Add as an alternative test env for maskinporten
standeren Nov 6, 2023
9875726
final fixes on content of multi-app-solution
standeren Nov 7, 2023
616e87c
Adapt maskinporten-app-integartion guide to be independant of multi-a…
standeren Nov 7, 2023
bc9fa37
Fix link
standeren Nov 7, 2023
a94caf9
added files required for mp doc
acn-sbuad Nov 7, 2023
37dcd57
Apply suggestions from code review
acn-sbuad Nov 7, 2023
9094eab
removed obsolete line
acn-sbuad Nov 7, 2023
223c3a0
re-wrote `An integration between the app and Maskinporten might be re…
acn-sbuad Nov 7, 2023
52535c2
fixed text in instructions section
acn-sbuad Nov 7, 2023
ede0f23
minor fixes to instrunction for app b
acn-sbuad Nov 7, 2023
c24aa6f
Fix comments from review
standeren Nov 8, 2023
b2439dd
Add expandable maskinporten guide in app-mp-integration guide
standeren Nov 8, 2023
ae44788
Merge branch 'master' into guide-multi-app-solution
standeren Nov 8, 2023
8568b66
Change formulation in prerequisites for instructions
standeren Nov 22, 2023
16d9ea4
Update content/app/guides/multi-app-solution/_index.en.md
standeren Nov 22, 2023
c972ae7
Update content/app/guides/multi-app-solution/_index.en.md
standeren Nov 22, 2023
a1f43cc
Update content/app/guides/multi-app-solution/_index.en.md
standeren Nov 22, 2023
4c21f0c
Update content/app/guides/multi-app-solution/_index.en.md
standeren Nov 22, 2023
8a4399d
Update content/app/guides/multi-app-solution/instructions/app-a/_inde…
standeren Nov 22, 2023
4d42702
Update content/app/guides/multi-app-solution/_index.en.md
standeren Nov 22, 2023
4f140be
Update content/app/guides/multi-app-solution/_index.en.md
standeren Nov 22, 2023
3909ea9
Update content/app/guides/multi-app-solution/testing/_index.en.md
standeren Nov 22, 2023
1187b4c
Update content/app/guides/multi-app-solution/_index.en.md
standeren Nov 22, 2023
cac3b1a
Update content/app/guides/multi-app-solution/_index.en.md
standeren Nov 22, 2023
bcb0be0
Update content/app/guides/multi-app-solution/instructions/app-a/_inde…
standeren Nov 22, 2023
0ead7fa
Update content/app/guides/multi-app-solution/instructions/app-a/_inde…
standeren Nov 22, 2023
2151b02
Merge branch 'master' into guide-multi-app-solution
standeren Nov 22, 2023
67269b1
Fix PR comments
standeren Nov 22, 2023
9d8eea2
Add norwegaian translation for maskinporten app integration
standeren Nov 22, 2023
fa15fd8
Merge branch 'master' into guide-multi-app-solution
standeren Nov 23, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
144 changes: 144 additions & 0 deletions content/app/guides/maskinporten-app-integration/_index.en.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,144 @@
---
title: Integrate Altinn app with Maskinporten
linktitle: Maskinporten-App integration
description: How to setup an integration between an Altinn App and Maskinporten.
weight: 100
toc: true
aliases:

- /app/maskinporten-app-integration/

---

This is a guide on how to set up an Altinn application to create a client that utilizes a Maskinporten integration for
its requests. This is a use case that is relevant when the application are going to perform requests that needs to
be authorized on behalf of the organization owning the application and not the end user owning the instance. By nature,
these requests will have credentials from the private user who logged in to the application and created the new
instance. In order to send these requests on behalf of the organization the following must be done;

1. Ensure organization has access to Azure key vault
2. Create the integration to Maskinporten
at [Samarbeidsportalen](https://samarbeid.digdir.no/)
3. Store the keys from the integration in Azure key vault for
the organisation
4. Set up the application to use the Maskinporten client by retrieving the secrets/keys from Azure key vault.

## Azure Key Vault Access
Before going forward in this guide, make sure you have access
to Azure key vault for your organization, so the keys
created further on in the guide can be added directly into
the secrets in Azure.

If access is missing, please refer to [Access to logs and secrets](../access-management/apps).

## Maskinporten Integration

In this section the Maskinporten client will be set up. A part of setting up the client includes creating keys that
should be stored in Azure Key vault later on in the guide. If different people in the organization have access to
different resources needed in this process, please cooperate and do the following steps on the same machine. This is
recommended to avoid sending secrets between machines.

When access to creating secrets in Azure key vault is
confirmed, please proceed to create the integration.

{{% expandlarge id="guide-mp-int-samarbeid" header="Guide on how to register a new Maskinporten integration in Samarbeidsportalen" %}}

{{% insert "/shared/guides/maskinporten-integration/maskinporten-integration-samarbeidsportal.txt" %}}

{{% /expandlarge %}}

## Azure Key Vault Configuration

When preparing the application to use the secrets from Azure Key vault, there are some steps that needs to be done:

1. Add the secrets retrieved during the Maskinporten client configuration to Azure Key vault:
- The base64 encoded JWT public and private key pair
- The clientID for the integration

It is important that the name of these secrets in Azure key vault corresponds
with the name of the section in the appsettings file in the
application repository. E.g. if your appsettings section for
the Maskinporten integration section looks like this:

```json
{
"MaskinportenSettings": {
"Environment": "ver2",
"ClientId": "",
"Scope": "altinn:serviceowner/instances.read",
"EncodedJwk": "",
"ExhangeToAltinnToken": true,
"EnableDebugLog": true
}
}
```

The secrets in Azure key vault should have names like this:

```
MaskinportenSettings--ClientId
MaskinportenSettings--EncodedJwk
```
2. For the application to be able to read the secrets from
Azure key vault the application need to be configured to
do so. See
the [secrets section](../../development/configuration/secrets)
to achieve this.
3. Add the appsettings section example
from above into the `appsettings.{env}.json` file.

_NB: The secrets are read by the application on start up so
if changing the secrets after the application is deployed, you
will need to redeploy the application._

## Setup Application to use Maskinporten Integration

When modifying the application to use the Maskinporten integration, we need to adapt the `program.cs` file.

First of all we need to add the MaskinportenHttpClient
service with the appropriate configuration in the function `RegisterCustomAppServices`:

```csharp
services.AddMaskinportenHttpClient<SettingsJwkClientDefinition, AppClient>(config.GetSection("MaskinportenSettings"));
```

Then we need to add the following function `ConnectToKeyVault` in the bottom of the file:

```csharp
static void ConnectToKeyVault(IConfigurationBuilder config)
{
IConfiguration stageOneConfig = config.Build();
KeyVaultSettings keyVaultSettings = new KeyVaultSettings();
stageOneConfig.GetSection("kvSetting").Bind(keyVaultSettings);
if (!string.IsNullOrEmpty(keyVaultSettings.ClientId) &&
!string.IsNullOrEmpty(keyVaultSettings.TenantId) &&
!string.IsNullOrEmpty(keyVaultSettings.ClientSecret) &&
!string.IsNullOrEmpty(keyVaultSettings.SecretUri))
{
string connectionString = $"RunAs=App;AppId={keyVaultSettings.ClientId};" +
$"TenantId={keyVaultSettings.TenantId};" +
$"AppKey={keyVaultSettings.ClientSecret}";
AzureServiceTokenProvider azureServiceTokenProvider = new AzureServiceTokenProvider(connectionString);
KeyVaultClient keyVaultClient = new KeyVaultClient(
new KeyVaultClient.AuthenticationCallback(
azureServiceTokenProvider.KeyVaultTokenCallback));
config.AddAzureKeyVault(
keyVaultSettings.SecretUri, keyVaultClient, new DefaultKeyVaultSecretManager());
}
}
```

Finally, this function must then be called in the
function `ConfigureWebHostBuilder`. The function already
exist, so just change the content to the following:

```csharp
void ConfigureWebHostBuilder(IWebHostBuilder builder)
{
builder.ConfigureAppConfiguration((_, configBuilder) =>
{
configBuilder.LoadAppConfig(args);
ConnectToKeyVault(configBuilder);
});
}
```
146 changes: 146 additions & 0 deletions content/app/guides/maskinporten-app-integration/_index.nb.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,146 @@
---
title: Integrasjon av Altinn-app med Maskinporten
linktitle: Maskinporten-App-integrasjon
description: Hvordan sette opp en integrasjon mellom en Altinn-app og Maskinporten.
weight: 100
toc: true
aliases:

- /app/maskinporten-app-integration/

---

Dette er en guide om hvordan du setter opp en Altinn-applikasjon for å opprette en klient som bruker en
Maskinporten-integrasjon for
sine forespørsler. Dette er relevant når applikasjonen skal utføre forespørsler som må
autentiseres på vegne av organisasjonen som eier applikasjonen, og ikke sluttbrukeren som eier instansen. Av naturen,
vil disse forespørslene ha legitimasjon fra den private brukeren som logget på applikasjonen og opprettet den nye
instansen. For å sende disse forespørslene på vegne av organisasjonen, må følgende gjøres;

1. Forsikre deg om at organisasjonen har tilgang til Azure Key Vault.
2. Opprett integrasjonen til Maskinporten
på [Samarbeidsportalen](https://samarbeid.digdir.no/).
3. Lagre nøklene fra integrasjonen i Azure Key Vault for
organisasjonen.
4. Sett opp applikasjonen til å bruke Maskinporten-klienten ved å hente hemmelighetene/nøklene fra Azure Key Vault.

## Tilgang til Azure Key Vault

Før du går videre i denne guiden, må du sørge for at du har tilgang
til Azure Key Vault for organisasjonen din, slik at nøklene
som opprettes senere i guiden, kan legges direkte inn i
hemmelighetene i Azure.

Hvis tilgang mangler, se [Tilgang til logger og hemmeligheter](../access-management/apps).

## Maskinporten-integrasjon

I denne delen blir Maskinporten-klienten satt opp. En del av oppsettet av klienten inkluderer opprettelse av nøkler som
skal lagres i Azure Key Vault senere i guiden. Hvis ulike personer i organisasjonen har tilgang til
forskjellige ressurser som trengs i denne prosessen, samarbeid og gjør de følgende trinnene på samme maskin. Dette er
anbefalt for å unngå å sende hemmeligheter mellom maskiner.

Når tilgang til å opprette hemmeligheter i Azure Key Vault er bekreftet, kan du fortsette med å opprette integrasjonen.

{{% expandlarge id="guide-mp-int-samarbeid" header="Guide om hvordan du registrerer en ny Maskinporten-integrasjon i Samarbeidsportalen" %}}

{{% insert "/shared/guides/maskinporten-integration/maskinporten-integration-samarbeidsportal.txt" %}}

{{% /expandlarge %}}

## Konfigurasjon av Azure Key Vault

Når applikasjonen forberedes på å bruke hemmelighetene fra Azure Key Vault, er det noen trinn som må gjøres:

1. Legg til hemmelighetene hentet under konfigurasjonen av Maskinporten-klienten i Azure Key Vault:
- Base64-kodet JWT offentlig og privat nøkkelpar
- Klient-ID for integrasjonen

Det er viktig at navnet på disse hemmelighetene i Azure Key Vault samsvarer
med navnet på seksjonen i appsettings-filen i
applikasjonsrepositoryet. For eksempel, hvis appsettings-seksjonen for
Maskinporten-integrasjonen ser slik ut:

```json
{
"MaskinportenSettings": {
"Environment": "ver2",
"ClientId": "",
"Scope": "altinn:serviceowner/instances.read",
"EncodedJwk": "",
"ExhangeToAltinnToken": true,
"EnableDebugLog": true
}
}
```

Hemmelighetene i Azure Key Vault burde ha navn som dette:

```
MaskinportenSettings--ClientId
MaskinportenSettings--EncodedJwk
```

2. For at applikasjonen skal kunne lese hemmelighetene fra
Azure Key Vault, må applikasjonen konfigureres til
å gjøre dette. Se
[seksjoner om hemmeligheter](../../development/configuration/secrets)
for å oppnå dette.
3. Legg til eksempel på appsettings-seksjonen
ovenfor i `appsettings.{env}.json`-filen.

_NB: Hemmelighetene leses av applikasjonen ved oppstart, så
hvis du endrer hemmelighetene etter at applikasjonen er publisert, må du
deploye applikasjonen på nytt._

## Sett opp applikasjonen til å bruke Maskinporten-integrasjonen

Når du endrer applikasjonen for å bruke Maskinporten-integrasjonen, må vi tilpasse filen `program.cs`.

For det første må vi legge til tjenesten MaskinportenHttpClient
med riktig konfigurasjon i funksjonen `RegisterCustomAppServices`:

```csharp
services.AddMaskinportenHttpClient<SettingsJwkClientDefinition, AppClient>(config.GetSection("MaskinportenSettings"));
```

Deretter må vi legge til følgende funksjon `ConnectToKeyVault` nederst i filen:

```csharp
static void ConnectToKeyVault(IConfigurationBuilder config)
{
IConfiguration stageOneConfig = config.Build();
KeyVaultSettings keyVaultSettings = new KeyVaultSettings();
stageOneConfig.GetSection("kvSetting").Bind(keyVaultSettings);
if (!string.IsNullOrEmpty(keyVaultSettings.ClientId) &&
!string.IsNullOrEmpty(keyVaultSettings.TenantId) &&
!string.IsNullOrEmpty(keyVaultSettings.ClientSecret) &&
!string.IsNullOrEmpty(keyVaultSettings.SecretUri))
{
string connectionString = $"RunAs=App;AppId={keyVaultSettings.ClientId};" +
$"TenantId={keyVaultSettings.TenantId};" +
$"AppKey={keyVaultSettings.ClientSecret}";
AzureServiceTokenProvider azureServiceTokenProvider = new AzureServiceTokenProvider(connectionString);
KeyVaultClient keyVaultClient = new KeyVaultClient(
new KeyVaultClient.AuthenticationCallback(
azureServiceTokenProvider.KeyVaultTokenCallback));
config.AddAzureKeyVault(
keyVaultSettings.SecretUri, keyVaultClient, new DefaultKeyVaultSecretManager());
}
}
```

Til slutt må denne funksjonen deretter kalles i
funksjonen `ConfigureWebHostBuilder`. Funksjonen finnes allerede,
så bare endre innholdet til følgende:

```csharp
void ConfigureWebHostBuilder(IWebHostBuilder builder)
{
builder.ConfigureAppConfiguration((_, configBuilder) =>
{
configBuilder.LoadAppConfig(args);
ConnectToKeyVault(configBuilder);
});
}
```
92 changes: 92 additions & 0 deletions content/app/guides/multi-app-solution/_index.en.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
---
title: Developing a multi-app solution in Altinn
linktitle: Multi-app solution
description: Considerations and explanations of how to go about when creating a multi-app solution
weight: 200
aliases:

- /app/multi-app-solution/

---

## What is a multi-app solution?
standeren marked this conversation as resolved.
Show resolved Hide resolved

A multi-app solution is a solution consisting of two or more
cooperating applications, where typically application A will trigger
the creation of a new
instance of application B. As a part of the
instantiation of application B it is possible to
prefill the instance with specific data from the running
instance of application A.

This guide takes you through a multi-app solution consisting of two
apps; _application A_ and _application B_,
but the concept can be extended to contain several applications of
type A or type B, or both types.

![Example architecture of a multi app solution](multi-app-architecture.drawio.svg)

### Terminology

- **An Instance**: When talking about instances in an
application-context, these are unique pieces of data that describes
details about the particular session going on in the application.
The data includes information on who is filling in
the data and what the data is.
- **Application A**: This will be an application that acts as a regular
Altinn application which means
end-users will interact with it. While filling in the form they will
be working on their own private instance. However
it will differ from other Altinn apps since the service owner
has customized it to include actions that
will create a new instance of the _application B_.
- **Application B**: This will be an application that may have multiple
purposes, but its main purpose will
be to receive and handle data from _application A_.
This application will differ from
other Altinn apps since instances are created by
triggers in another application.

## Do I need a multi-app solution?

Altinn offers a robust set of APIs and event support for processing data from Altinn Apps. However, if these options do
not align with your needs, you might consider a multi-app solution.

### Use cases where you can consider using a multi-app solution:

standeren marked this conversation as resolved.
Show resolved Hide resolved
acn-sbuad marked this conversation as resolved.
Show resolved Hide resolved
We have outlined some common use cases that may warrant the multi-app approach.
- The organization has limited development capacity or does not want
to develop and maintain a new system for processing data from
Altinn.
- Existing setup within the organization for processing data from
Altinn does not satisfy requirements for security.

By implementing a multi-app solution, an organization can use the Altinn inbox for their organization to receive data. In
most cases the people required to process the data will already have access to the organization in Altinn or can be
granted this access. The last application in the data flow (application B in our case), can set authorization rules
requiring a specific role before granting access to the data, hence supporting limiting access to sensitive data to
people with an official need.

## How does the multi-app solution actually work?

standeren marked this conversation as resolved.
Show resolved Hide resolved
A multi-app solution is a way of configuring multiple forms to communicate through API calls. The specific communication
we will describe in this guide is the creation of a new instance of an application (B) triggered by another application
(A). A typical scenario would be that an end-user fills out or uploads information in an instance of application A. And when pressing
the button to submit the form, an API call is sent to another application (B), creating a new instance of this application where
the answers from application A is a part of the information.

### An integration between the app and Maskinporten might be required

In order for an application to perform actions on another application such as creating a new instance on behalf of
and end user or organisation, it needs to be authorized.
By nature, the request to create the instance of application B will include the credentials of the end user
filling out application A.
In most cases this end user will not be authorized to instantiate new instances on behalf of the
organisation that owns application B, thus this will fail.
A way to ensure the application is authorized to perform the instantiation action, is to use the
application owners credentials instead of the end user's credentials.
This is achieved by using a Maskinporten integration to generate a token that represents the organisation
and adding this token to the requests that application A makes towards application B.


{{<children description="true" />}}
Loading