Configuração do Servidor
Todas as chaves que o Servidor lê, o padrão de cada uma, se um Administrador pode alterá-la em tempo de execução e se uma alteração exige reinício. O Workstation Service e o Tray App são configurados à parte: veja Configuração das estações de trabalho.
De onde vem um valor
Seis fontes, da menor para a maior precedência. Uma fonte posterior prevalece sobre uma anterior, chave por chave:
| Fonte | Onde existe | |
|---|---|---|
| 1 | appsettings.json | Embutido na imagem. Não é um arquivo que a implantação edita. |
| 2 | appsettings.{ASPNETCORE_ENVIRONMENT}.json | O appsettings.Development.json está na imagem e fica inerte porque uma implantação não é o ambiente Development. Nunca execute uma implantação como Development: esse arquivo contém a licença de exemplo do PKI SDK e as credenciais de um Signer de teste compartilhado. |
| 3 | User secrets | Somente na máquina de um desenvolvedor. |
| 4 | Variáveis de ambiente | O container: o environment: do Compose ou os application settings do App Service. __ substitui :. |
| 5 | Linha de comando | Nenhum dos dois cenários usa. |
| 6 | Os overrides que um Administrador salvou | Uma tabela no banco de dados da plataforma, lida na inicialização e relida sempre que uma configuração é salva na tela Configurações e usuários. |
A fonte 6 é silenciosa e prevalece. Se você define uma das sete chaves que aceitam override na implantação e o valor não tem efeito, alguém salvou um valor na tela Configurações e usuários; o seu valor é o padrão para o qual a chave volta quando o override é limpo.
| Chave que um Administrador pode sobrescrever | Padrão |
|---|---|
Sessions:DefaultDuration | 1 h |
Sessions:MaxDuration | 24 h |
Sessions:PinPromptTimeout | 60 s |
Sessions:MaxPinFailures | 5 |
Sessions:PinFailureWindow | 15 min |
Signing:WorkstationReconnectGrace | 15 s |
Audit:RetentionDays | 365 |
Essas sete entram em vigor sem reinício. Uma linha salva com qualquer outra chave é ignorada, e não aplicada. Trate todas as outras chaves desta página como exigindo reinício.
Como escrever uma chave
: num arquivo, __ no ambiente:
{ "Sessions": { "MaxDuration": "12:00:00" } }
environment:
Sessions__MaxDuration: "12:00:00"
az webapp config appsettings set -g <rg> -n <app> --settings Sessions__MaxDuration=12:00:00
- Um único sublinhado não faz nada:
Sessions_MaxDurationé uma variável que o Servidor nunca lê. - Uma lista é indexada, e o índice faz parte da chave:
KeyRingProtector__RetiredCertificates__0__Certificate. - Uma duração é
[d.]hh:mm:ss, e as horas precisam ficar abaixo de 24.24:00:00são vinte e quatro dias; um dia é1.00:00:00. - Um tamanho é uma contagem simples de bytes. Um booleano é
trueoufalse, em minúsculas. - Uma categoria de log mantém os pontos:
Logging__LogLevel__TrustBridge.Server.Common.Vault.
Banco de dados e chaveiros
ConnectionStrings:TrustBridge
Padrão uma string local com autenticação do Windows, só para desenvolvimento · Override pelo Administrador não · Exige reinício sim
O único banco de dados da plataforma: schema, Trilha de Auditoria, os dois chaveiros e os overrides do Administrador. O padrão da imagem não funciona no Linux, então uma implantação que esquecer esta chave tem a inicialização recusada depois de cerca de noventa segundos de tentativas.
Um Command Timeout na string é o padrão, e não um teto para tudo. Alguns comandos têm limite
próprio, qualquer que seja o valor da string: a aplicação do schema, o probe de saúde, a transferência
ou a exclusão de um pacote de Versão da Estação de Trabalho e cada gravação na Trilha de Auditoria, que
recebe quinze segundos. Command Timeout=0, que significa sem limite, continua valendo para todo o
resto.
No PostgreSQL, ela segue a grafia do Npgsql (Host=, Username=, SSL Mode=), com
Database:Engine definida como PostgreSql ao lado; uma string que só o driver do
SQL Server lê recusa a inicialização. Ela aponta para o próprio PostgreSQL, e não para um pooler em modo
de transação (o do PgBouncer, ou o do Azure Database for PostgreSQL na porta 6432): o lock da etapa do
schema é mantido por uma única sessão do banco, e um pooler assim executa os comandos de uma conexão em
várias. Duas chaves valem a pena nela: SSL Mode=Require ou mais rigorosa para qualquer banco que a
conexão precise sair do host para acessar, porque o padrão do Npgsql volta para texto simples quando o
servidor não oferece TLS; e GSS Encryption Mode=Disable, porque a imagem não traz biblioteca Kerberos,
e sem ela a primeira conexão procura uma e o log ganha um erro Cannot load library libgssapi_krb5.so.2 que não muda nada.
# Docker on Linux, SQL Server beside it
ConnectionStrings__TrustBridge: >-
Server=sqlserver,1433;Database=TrustBridge;User Id=sa;
Password=${MSSQL_SA_PASSWORD};Encrypt=True;TrustServerCertificate=True
# Docker on Linux, PostgreSQL beside it
Database__Engine: PostgreSql
ConnectionStrings__TrustBridge: >-
Host=postgres;Port=5432;Database=trustbridge;Username=trustbridge;
Password=${POSTGRES_PASSWORD};GSS Encryption Mode=Disable
# Azure App Service, managed identity
ConnectionStrings__TrustBridge="Server=tcp:<sqlserver>.database.windows.net,1433;Database=TrustBridge;Authentication=Active Directory Managed Identity;Encrypt=True"
Database:Engine
Padrão SqlServer · Override pelo Administrador não · Exige reinício sim
O mecanismo de banco de dados em que roda o banco deste Servidor: SqlServer (SQL Server ou Azure SQL)
ou PostgreSql (PostgreSQL 16 ou posterior, sem nenhuma extensão), sem diferenciar maiúsculas de
minúsculas. Desde o Servidor 1.20.0 os dois drivers vêm na mesma imagem, e esta chave escolhe qual o
Servidor usa. Uma implantação escolhe o mecanismo uma vez, na instalação: nenhuma implantação muda de
mecanismo, e apontar uma implantação existente para o outro é apontá-la para um banco de dados
diferente e vazio, sem administradores, sem trilha e com um cofre que nunca guardou nada. Nada move os
dados de uma instalação em funcionamento de um mecanismo para o outro.
O PostgreSQL só é suportado na forma com Docker. A forma com App Service continua no Azure SQL, com a identidade gerenciada. Nada no Servidor recusa o PostgreSQL ali, então deixe esta chave no padrão no App Service (Azure App Service).
Uma connection string escrita para o outro mecanismo recusa a inicialização, com uma linha
Critical citando esta chave e ConnectionStrings:TrustBridge, antes de qualquer acesso ao banco. O
mesmo vale para um valor que não cite nenhum dos dois mecanismos, inclusive um número ou dois nomes
separados por vírgula. Uma string mínima como Server=…;Database=…;User Id=…;Password=… é lida pelos
dois drivers e passa; a recusa é para uma string que só o outro mecanismo lê: Host=, Username= ou
SSL Mode= com SQL Server, Encrypt=, Data Source= ou Initial Catalog= com PostgreSQL.
No PostgreSQL, o Servidor cria o banco de dados quando ele não existe, como faz no SQL Server,
conectando-se ao banco postgres para isso; então a identidade precisa de CREATEDB nessa primeira
inicialização, ou um DBA cria o banco vazio antes. Aplicar migrações exige CREATE no schema public
(ou ser dono dele). Para aplicá-las manualmente, informe também o mecanismo à ferramenta
(Instalação do Servidor):
dotnet ef database update --project src/TrustBridge.Server \
--connection "Host=…;Database=trustbridge;…;Command Timeout=3600" -- --Database:Engine=PostgreSql
environment:
Database__Engine: PostgreSql
Database:MigrateOnStart
Padrão true · Override pelo Administrador não · Exige reinício sim
Se o Servidor aplica as migrações pendentes ao banco de dados na inicialização, antes de atender
qualquer coisa. false não significa "iniciar mesmo assim": uma migração pendente, nesse caso,
recusa a inicialização, citando as migrações e o comando a executar. Dois estados recusam a
inicialização qualquer que seja o valor: um banco de dados com migrações que este build não contém, e
um banco de dados que não pode ser acessado em cerca de noventa segundos. Aplicar migrações exige
db_ddladmin (no PostgreSQL, CREATE no schema public); um banco de dados atualizado não precisa de
nenhum DDL.
Três limites de tempo são constantes, e não chaves: cerca de noventa segundos para o banco de dados
começar a responder, cinco minutos para a migração de outro processo terminar e trinta minutos para
cada comando de uma migração. No Azure App Service, o WEBSITES_CONTAINER_START_TIME_LIMIT (padrão
de 230 s) é atingido primeiro; aumente-o para 1800.
KeyRingProtector:Certificate
Padrão não definido · Override pelo Administrador não · Exige reinício sim
Obrigatória em toda implantação, inclusive numa que não guarda certificados próprios. Um PKCS#12 codificado em base64, numa única linha e sem header PEM, com uma chave privada RSA. Não é um caminho nem um thumbprint. Quatro recusas impedem o host de iniciar: não configurada, não é base64, não pôde ser aberta (senha errada ou não é um PKCS#12) e nenhuma chave privada RSA utilizável. Veja Segurança.
environment:
KeyRingProtector__Certificate: ${KEY_RING_PROTECTOR_CERTIFICATE:?set KEY_RING_PROTECTOR_CERTIFICATE in .env}
# App Service: an app setting, or better, a Key Vault reference
KeyRingProtector__Certificate="@Microsoft.KeyVault(SecretUri=https://<vault>.vault.azure.net/secrets/<name>/)"
KeyRingProtector:CertificatePassword
Padrão não definido · Override pelo Administrador não · Exige reinício sim
A senha que abre o protetor. Ausente significa que o PKCS#12 não precisa de senha, que é o padrão honesto para um protetor fornecido como configuração.
KeyRingProtector:RetiredCertificates:{n}:Certificate e …:{n}:CertificatePassword
Padrão vazio · Override pelo Administrador não · Exige reinício sim
Protetores que esta implantação já usou para selar, mantidos para que o material de chave selado com
um deles continue legível. Só para decifrar, e mantidos permanentemente: a rotação nunca
re-cifra as chaves armazenadas. É uma lista de objetos, porque cada PKCS#12 aposentado tem a própria
senha, pareada pelo índice. Não coloque uma entrada vazia em templates: uma entrada cujo
Certificate resulta numa string vazia recusa a inicialização.
environment:
KeyRingProtector__Certificate: <the new one>
KeyRingProtector__RetiredCertificates__0__Certificate: <the one it replaced>
KeyRingProtector__RetiredCertificates__0__CertificatePassword: <if that one had a password>
Logs
Logging:LogLevel:{category}
Padrão Information, com Microsoft.AspNetCore em Warning · Override pelo Administrador não · Exige reinício sim
Os níveis de log do framework, e o único lugar em que um nível é decidido: o console, o arquivo
rotativo e o Application Insights recebem exatamente as linhas que esses níveis deixam passar. Sete
categorias trazem as linhas que vale a pena reconhecer, todas em Information ou acima, então o
padrão já as mostra:
| Categoria | O que informa |
|---|---|
TrustBridge.Server.Common.Persistence.SchemaUpgrade | Quais migrações foram aplicadas nesta inicialização, ou por que o schema foi recusado |
TrustBridge.Server.Common.Persistence.SchemaGate | Que os overrides do Administrador não puderam ser relidos depois da etapa do schema |
TrustBridge.Server.Common.KeyRings.KeyRingPosture | Qual protetor está selando agora, com o thumbprint e o número de aposentados |
TrustBridge.Server.Common.Vault.VaultReadiness | Se o cofre está desligado, aberto ou travado fechado |
TrustBridge.Server.Common.Audit.AuditLog | Uma linha de auditoria que não conseguiu chegar ao banco de dados, em Critical, com a própria linha |
TrustBridge.Server.Common.Licensing.PkiLicenseGate | Que o PKI SDK recusou a licença deste Servidor, de modo que nem a frota nem o cofre conseguem assinar até ela ser renovada, ou que não há licença e o Servidor não vai iniciar |
TrustBridge.Pki.Validation.LacunaPkiRuntime | Que o PKI SDK está licenciado e pronto na inicialização, e onde ficam os caches dele. Em Error, por que uma licença configurada não pôde ser carregada |
Aumente o nível de uma categoria, não o nível mínimo geral: o log de debug do framework soterra essas sete linhas.
Logging:File:Directory
Padrão trustbridge-logs no diretório temporário do processo (/tmp/trustbridge-logs) · Override pelo Administrador não · Exige reinício sim
Onde o arquivo rotativo em JSON compacto é gravado, um por dia, com nova rotação ao passar de um
gigabyte. A tela Log do Servidor do console administrativo lê esse arquivo. Vazio desliga o
arquivo, que é o que um sistema de arquivos somente leitura define. Um diretório que o Servidor não
consegue criar deixa o arquivo desligado durante toda a vida do processo, com um Warning; o console
não é afetado.
Logging:File:RetainedDays
Padrão 14 · Override pelo Administrador não · Exige reinício sim
Quantos dias de arquivos são mantidos. Abaixo de 1, a inicialização é recusada. É um limite de uso de disco, e não uma política de retenção: o pipeline do console é o registro.
Logging:ApplicationInsights:ConnectionString
Padrão não definido · Override pelo Administrador não · Exige reinício sim
Uma connection string do Application Insights. Quando definida, toda linha também é enviada para lá
como um trace, com o id de correlação e a categoria como dimensões personalizadas. Quando não
definida, APPLICATIONINSIGHTS_CONNECTION_STRING é lida no lugar dela, então um workspace associado
pelo portal do App Service não precisa de uma segunda configuração. Um valor que não seja uma
connection string recusa a inicialização.
AllowedHosts
Padrão * · Override pelo Administrador não · Exige reinício sim
O filtro de header Host do framework. Nenhum dos dois cenários precisa dele.
Para uma Assinatura de teste funcionar, uma lista aqui precisa incluir o host do loopback:
localhost (ou 127.0.0.1, onde o Servidor escuta em 0.0.0.0), ou o host que
TestSignature:LoopbackAddress indica. Uma execução chama o contrato do próprio
Servidor com esse nome no header Host, e o filtro responde com um 400 simples a tudo o que ele não
lista: toda Assinatura de teste falha, e o log diz apenas que POST /v1/sessions respondeu 400 sem
envelope de erro. Isso vale tanto para a página de Assinatura de teste do console administrativo quanto
para a pública.
Atrás de um proxy reverso
Quem o Servidor acredita que está chamando. Uma implantação sem nada na frente não define nada aqui, e o App Service também não, porque usa a opção do próprio framework.
Três coisas leem o endereço de quem chama: o limite por endereço da admissão
(Admission:RequestsPerAddress), o limite de desafios do Acesso
com Certificado (Admin:CertificateSignIn:Enabled) e o ClientIp
de toda linha de auditoria. Por padrão, é o endereço da conexão; atrás de um proxy reverso, então, é o
endereço do proxy, e todos os clientes viram um só. Citar o proxy faz o Servidor aceitar
X-Forwarded-For e X-Forwarded-Proto vindos dele, e de mais ninguém.
Há duas formas de ligar isso, e uma implantação usa uma delas:
| Configuração | Para | Confia em |
|---|---|---|
ForwardedHeaders:TrustedProxies | Um proxy que você opera e consegue citar: Docker atrás de nginx, HAProxy ou um balanceador de carga | Nos endereços listados, por tantos saltos quantos forem listados |
ASPNETCORE_FORWARDEDHEADERS_ENABLED=true | O App Service, cujos front ends não podem ser listados | Em quem se conectar, por um salto. Só é seguro porque o container é acessível por esses front ends e por nada mais |
Definir as duas recusa a inicialização. Uma implantação Docker que definiu
ASPNETCORE_FORWARDEDHEADERS_ENABLED seguindo um guia antigo continua funcionando, confiando em quem se
conectar, e registra um Warning na inicialização avisando disso; passe a usar a lista.
environment:
ForwardedHeaders__TrustedProxies__0: "10.0.0.5"
ForwardedHeaders__TrustedProxies__1: "10.0.1.0/24"
ForwardedHeaders:TrustedProxies
Padrão vazio, o que significa o próprio endereço da conexão · Override pelo Administrador não · Exige reinício sim
Os proxies cujos X-Forwarded-For e X-Forwarded-Proto este Servidor considera. Cada entrada é um
endereço (10.0.0.5) ou uma rede em notação CIDR (10.0.1.0/24), IPv4 ou IPv6. Uma conexão de
qualquer outro lugar tem os dois headers ignorados, então um cliente que chega ao Servidor contornando o
proxy não consegue informar o próprio endereço. Considerar X-Forwarded-Proto é o que dá a um proxy que
termina o TLS cookies Secure e redirecionamentos de login para https://.
- Liste o proxy, não a rede em que estão os clientes dele. Um cliente dentro de uma rede listada é tratado como proxy e pode informar o endereço que quiser.
- É uma lista, mesmo com um item. No ambiente, toda entrada leva um índice,
ForwardedHeaders__TrustedProxies__0.ForwardedHeaders__TrustedProxies=10.0.0.5seria descartada sem aviso, então o Servidor recusa a inicialização. - Uma cadeia é percorrida de volta até o primeiro endereço não listado. Com um balanceador de carga
na frente do proxy, liste os dois. Um proxy na borda deve substituir o
X-Forwarded-Forpelo endereço que viu (o$remote_addrdo nginx); um proxy atrás de um balanceador listado deve acrescentar ao header (o$proxy_add_x_forwarded_fordo nginx). Um proxy atrás de um balanceador que termina o TLS repassa oX-Forwarded-Protodo balanceador, em vez de trocá-lo porhttp. - Só o endereço e o esquema.
X-Forwarded-HosteX-Forwarded-Prefixnunca são considerados, e o header padrãoForwarded(RFC 7239) não é lido. O proxy precisa repassar o headerHostdo navegador (no nginx,proxy_set_header Host $host), ou o redirecionamento de login aponta para o endereço do upstream.
A inicialização é recusada para uma lista que confiaria nos pares errados:
| Entrada | Por que é recusada |
|---|---|
0.0.0.0/0, ::/0 | Confia em todo mundo. |
Bits definidos além do prefixo, como 10.0.0.5/24 | É assim que uma interface imprime o próprio endereço; lida como rede, confiaria na sub-rede inteira. |
Fora do formato decimal com pontos, como 010.0.0.5, 10 ou 0x0a000005 | O parser as lê como outras máquinas. Escreva o endereço como o Servidor o imprime. |
IPv4 na forma IPv6 (::ffff:10.0.0.5) | Escreva o endereço IPv4; ele também corresponde à forma dual-stack. |
IPv6 link-local (fe80::…) | O Servidor vê esse par com um escopo anexado, então a entrada nunca corresponderia. |
| Algumas redes IPv6 | As que o .NET 10 interpretaria erradamente como contendo clientes IPv4. Um endereço IPv6 exato é sempre seguro, assim como uma rede de /96 ou menos cujo comprimento seja múltiplo de 8 (/32, /48, /64). |
| Algo que não é um endereço | Citada pelo índice. |
Um único valor sem índice, ou qualquer outra chave sob ForwardedHeaders (como KnownProxies) | De outro modo, não seria lida por nada. |
Definida junto com ASPNETCORE_FORWARDEDHEADERS_ENABLED | A opção do framework já confia em todo mundo, então a lista não restringiria nada. |
Quando as linhas de auditoria continuam mostrando o proxy, leia a linha de inicialização que começa
com Forwarded headers:: ela cita a lista, diz que nada é considerado, ou avisa que
ASPNETCORE_FORWARDEDHEADERS_ENABLED confia em quem se conectar. Uma conexão de um par que a lista não
cita só é registrada em Debug, na categoria Logging:LogLevel:Microsoft.AspNetCore.HttpOverrides;
aumente o nível dela enquanto verifica de qual endereço o proxy realmente se conecta.
Configuração da implantação, e nunca uma tela: quais máquinas podem falar pelo endereço de quem chama é um fato da rede na frente do Servidor, e um valor errado é um jeito de contornar todas as regras por endereço.
O serviço de assinatura
Onde fica o Lacuna Signer e como o TrustBridge se autentica nele. As duas coisas ou nenhuma: um
Signer não configurado é uma implantação suportada, em que /v1/signatures recusa as chamadas e todo
o resto funciona; um endereço sem chave recusa a inicialização.
environment:
Signer__BaseAddress: https://signer.example.com
Signer__ApiKey: My Application|43fc0da834e48b4b840fd6e8c371…
Signer__ApplicationName: My Application # only for a key that is the secret half alone
Signer__FolderId: f81d4fae-7dec-11d0-a765-00a0c91e6bf6
Signer__RequestTimeout: "00:00:10"
| Chave | Padrão | Significado |
|---|---|---|
Signer:BaseAddress | não definido | O endereço base do Signer. Defini-lo torna ApiKey obrigatória. |
Signer:ApiKey | não definido | A única chave de API do Signer que o TrustBridge guarda em nome de todas as Aplicações Cliente, na forma completa application|secret que o Signer publica. |
Signer:ApplicationName | não definido | A parte da aplicação, só para uma chave que traga apenas o secret. Ignorada quando a chave contém |. |
Signer:FolderId | não definido | A pasta do Signer em que todos os documentos são colocados, como GUID. Não definida, é a raiz da organização. |
Signer:RequestTimeout | 10 s | O limite de uma chamada ao Signer. Um valor não positivo recusa a inicialização. |
Todas exigem reinício, e nenhuma aceita override.
REST PKI Core
Onde fica o REST PKI Core e como o TrustBridge se autentica nele: o mecanismo com que uma Aplicação Cliente assina os documentos depois que um Administrador liga Assinar documentos com o REST PKI Core no cartão dela, na tela Aplicações Cliente (Servidor 1.18.0 e posteriores). O REST PKI Core monta o PAdES em torno da única assinatura do titular e guarda o documento assinado; o Servidor o busca lá quando o cliente pede. O integrador não vê nenhuma diferença no protocolo.
As três ou nenhuma. Uma implantação que não define nenhuma delas inicia como sempre, e a tela
Aplicações Cliente recusa passar uma aplicação para o REST PKI Core, com o único motivo de que ele não
está configurado. Algumas sem as outras recusam a inicialização, citando o que falta. Uma aplicação
que já usa o REST PKI Core num Servidor que perdeu a seção tem cada chamada de assinatura recusada antes
de qualquer chave ser usada, como 500 INTERNAL_ERROR, com uma linha Error.
environment:
RestPkiCore__Endpoint: https://core.pki.rest/
RestPkiCore__ApiKey: TrustBridge|3c6a0f…
RestPkiCore__SecurityContextId: 201856ce-273c-4058-a872-8937bd547d36
| Chave | Padrão | Significado |
|---|---|---|
RestPkiCore:Endpoint | não definido | O endereço da instância do REST PKI Core: absoluto e https, porque a chave de API vai em toda requisição, e com um caminho terminado em barra, ou o cliente descarta o último segmento e toda chamada vira um 404. Qualquer um dos dois erros recusa a inicialização. |
RestPkiCore:ApiKey | não definido | A chave de API de uma aplicação do REST PKI Core com o role Worker, apresentada como X-Api-Key. É um segredo: defina-a a partir de um cofre de segredos ou de uma variável de ambiente, nunca num arquivo versionado. |
RestPkiCore:SecurityContextId | não definido | O contexto de segurança sob o qual o REST PKI Core valida o certificado do titular e assina, pelo GUID. Um valor que não é um GUID recusa a inicialização. O exemplo é o contexto padrão ICP-Brasil do REST PKI Core, PkiBrazil. |
Todas exigem reinício, e nenhuma aceita override.
Uma seção que o REST PKI Core não atende é uma falha desta implantação, e não uma
indisponibilidade. Uma chave que ele recusa (401), uma chave cuja aplicação não tem o role Worker
(403) ou um contexto de segurança que ele não tem respondem toda chamada de assinatura com
500 INTERNAL_ERROR, com uma linha Error dizendo qual. O REST PKI Core inacessível, com falha,
limitando requisições ou sem cota é 502 SIGNER_ERROR, que um cliente pode tentar de
novo. Qualquer outra resposta do REST PKI Core que este Servidor não interpreta também é
500 INTERNAL_ERROR, com uma linha Error trazendo o status do REST PKI Core. O REST PKI Core é chamado
pedindo respostas em inglês, para que as mensagens dele cheguem ao log no idioma do log.
O que se define do lado do REST PKI Core
Três coisas decidem como fica um documento assinado ali, e nenhuma delas é uma chave daqui:
- A confiança é do contexto de segurança, e não das Autoridades Certificadoras Confiáveis. O REST
PKI Core valida o certificado do titular sob o contexto que
SecurityContextIdindica, uma vez antes de o titular ser consultado e de novo ao assinar, e recusa um certificado em que não confia como422 CERT_NOT_ACTIVE. O veredito do próprio Servidor continua controlando toda assinatura, então os dois são consultados em sequência e podem discordar. Uma implantação cujos titulares vêm de ACs além da ICP-Brasil precisa de um contexto de segurança personalizado, criado no dashboard do REST PKI Core por um usuário com o role Manager e mantido em sincronia com a tela de Autoridades Certificadoras Confiáveis manualmente: nada reflete um no outro. O REST PKI Core também verifica a revogação na hora, então a janela de tolerância deste Servidor para uma AC inacessível não vale ali, a menos que o contexto esteja configurado para ignorar um status de revogação desconhecido. - A política de assinatura é da instância do REST PKI Core. ICP-Brasil AD-RB, sem carimbo de
tempo, exige
General:UseBrazilianPdfSigningPoliciesligada na instância (é desligada por padrão, o que assina um PAdES Basic simples) eGeneral:DefaultSignaturePolicymantida emBasic(WithTimeacrescenta um carimbo de tempo). Numa instância própria, quem a opera define as duas; na instância hospedada da Lacuna, elas são da Lacuna, então pergunte antes de contar com a política. - As marcas nas páginas são da organização no REST PKI Core. O REST PKI Core pode carimbar nas páginas
um link para a página dele sobre o documento antes de calcular o hash, de modo que o PDF marcado é o
que o titular assina. Se ele faz isso depende da política de marcação de PDF
da organização, ou então da
Pdf:MarkingPolicyda instância, cujo padrão éWhenPossible. Defina-a como Never numa implantação cujos documentos não devem trazer nada além da assinatura.
O Servidor precisa acessar dois endereços do REST PKI Core, e não um. Endpoint é o endereço que
ele chama. Um documento assinado é baixado de uma URL que o REST PKI Core responde, que traz um tíquete de
acesso de curta duração e nunca é guardada, e o host dela é o endereço do site da própria instância,
não necessariamente o endpoint configurado aqui. Uma implantação que acessa o REST PKI Core por um nome
interno, ou atrás de uma lista de saídas permitidas, precisa deixar o Servidor sair também para esse
endereço do site, ou todo download de um documento do REST PKI Core falha (502 SIGNER_ERROR onde ele
é inacessível, 500 INTERNAL_ERROR com uma linha Error onde ele responde um 4xx), enquanto todas as
assinaturas dão certo. Esse download não leva chave de API e lê no máximo o dobro de
Signing:MaxDocumentBytes.
O REST PKI Core guarda o documento assinado; este Servidor não guarda nada. Por quanto tempo um
documento continua disponível depende do que a instância faz, e um que ela não tem mais é
422 DOCUMENT_UNAVAILABLE, como um documento do Signer que deixou de existir. Voltar uma aplicação para o
Signer é sempre permitido, e os documentos que o REST PKI Core assinou continuam disponíveis nele depois
disso.
Como o prazo de assinatura limita uma chamada assinada ali
Signing:RequestBudget cobre, como um único prazo, o upload validado do
certificado na admissão e a execução de cada documento até a assinatura do titular: o tempo do upload é
descontado do prazo de cada execução, individual ou em lote. A Autorização de assinatura no Tray App,
numa sessão com PIN por transação "workstation", fica entre os dois e não é contada. Depois que a
chave do titular assinou, a conclusão recebe um limite próprio, do mesmo tamanho do prazo, que nem o
prazo nem um cliente que desiste da conexão interrompem, para que um documento assinado nunca fique
abandonado no REST PKI Core por falta de tempo. Assim, uma chamada pode passar do prazo em até esse tanto
depois que a chave assinou, e por isso Signing:StrandedAfter precisa ser maior que o dobro do prazo.
Cada chamada ao REST PKI Core também é limitada pelo timeout de 60 segundos do próprio cliente, que não é
uma chave daqui.
Sessões de Assinatura
Cinco das sete chaves que aceitam override do Administrador estão aqui. Uma chave desta seção não é
mais lida: Sessions:SignatureAllowance, cujo valor é definido por
Aplicação Cliente desde o Servidor 1.17.0.
environment:
Sessions__DefaultDuration: "01:00:00"
Sessions__MaxDuration: "1.00:00:00"
Sessions__MaxPinFailures: "5"
Sessions__PinFailureWindow: "00:15:00"
Sessions__PinPromptTimeout: "00:01:00"
Sessions__PinRelayTimeout: "00:00:05"
Sessions__ExpirySweepInterval: "00:05:00"
| Chave | Padrão | Override | Reinício | Significado |
|---|---|---|---|---|
Sessions:DefaultDuration | 1 h | sim | não | A janela de ociosidade concedida quando o cliente não pede nenhuma. Um valor não positivo recusa a inicialização. |
Sessions:MaxDuration | 24 h (1.00:00:00) | sim | não | A maior janela que um cliente pode pedir; um pedido maior é reduzido a esse limite, e o valor reduzido é devolvido. Abaixo de DefaultDuration, recusa a inicialização. |
Sessions:MaxPinFailures | 5 | sim | não | Comparações de PIN com falha, dentro da janela, que bloqueiam um CPF para criação de sessão, contadas por CPF somando todas as chaves de API. É também o tamanho dos limites de provas com falha descritos abaixo. Zero recusa a inicialização. |
Sessions:PinFailureWindow | 15 min | sim | não | A janela deslizante do bloqueio e o tempo de espera, e a janela em que os limites de provas com falha são contados. Um valor não positivo recusa a inicialização. |
Sessions:PinPromptTimeout | 60 s | sim | não | Por quanto tempo um pedido de PIN no Tray App fica na tela antes de a criação desistir. Quando esse prazo acaba, o Servidor tira o pedido da tela de uma máquina no protocolo 5 na hora. O Tray:PromptTimeout da própria estação de trabalho (90 s) é mais folgado de propósito, e é o que encerra um pedido que o Servidor não consegue acessar. |
Sessions:PinRelayTimeout | 5 s | não | sim | Quanto tempo a passagem pelo PIN em cache espera as respostas das máquinas. Todas as máquinas candidatas são desafiadas ao mesmo tempo dentro dele, e não uma de cada vez, então uma máquina que nunca responde custa isso e nada mais. A verificação da resposta de um Certificado A1 acontece depois, no Servidor. Um valor não positivo recusa a inicialização. O nome é o do antigo repasse do PIN e foi mantido por ser uma chave de configuração. |
Sessions:ExpirySweepInterval | 5 min | não | sim | A frequência com que a varredura encerra no registro as sessões vencidas. Não muda nenhum veredito. Não é validada na inicialização. |
Os limites de PIN com falha
Sessions:MaxPinFailures dentro de Sessions:PinFailureWindow define três limites de uma vez. Reduzir
o número aperta os três.
| Limite | O que conta | Quando se esgota |
|---|---|---|
| O bloqueio do CPF | Comparações de PIN com falha para um CPF, no máximo uma por requisição, somando todas as chaves de API | A criação de sessão para esse CPF responde TOO_MANY_PIN_ATTEMPTS até as falhas saírem da janela. Uma criação bem-sucedida não as zera; elas saem da janela com o tempo. |
| O limite de provas com falha de uma estação de trabalho | Provas de PIN (PIN Proofs) que uma máquina deu para um CPF e que não conferiram, mesmo que outra candidata tenha correspondido, exceto numa criação em que uma prova da própria máquina conferiu | Essa máquina não recebe desafio de PIN nem pedido de PIN para esse CPF e é considerada inacessível para esse titular até as falhas saírem da janela. Registrado em Warning e auditado como pin.proof-budget-spent. |
| O limite do Cofre de Certificados | Senhas que o cofre tentou para um CPF e que não abriram nada, uma vez por criação, mesmo que outra candidata tenha correspondido | O cofre não tenta nenhuma para esse CPF até elas saírem da janela. Ele continua candidato, mas não é tentado, então o cliente recebe PIN_NOT_AVAILABLE em vez de WORKSTATION_OFFLINE. Auditado como pin.proof-budget-spent, sem citar máquina. |
As falhas de uma máquina nunca contam contra outra, mas a própria máquina do titular pode ser deixada de lado antes de o bloqueio disparar: um PIN errado custa a ela uma prova com falha para cada certificado do titular que ela guarda para a sessão, enquanto o bloqueio conta uma. Um titular que se vincula por um token cujo PIN não é a senha dele no cofre também gasta o limite do cofre, e vê o cofre deixado de lado depois dessa quantidade de sessões assim dentro da janela.
Sessions:SignatureAllowance
Não é mais lida desde o Servidor 1.17.0 · Override pelo Administrador — · Exige reinício —
Esta chave limitava todas as Sessões de Assinatura da implantação pelo número de chamadas de assinatura que cada uma podia fazer. A Franquia de Assinaturas agora é definida por Aplicação Cliente: um Administrador a define, altera ou remove no cartão da aplicação, na tela Aplicações Cliente, e uma sessão recebe a franquia da Aplicação Cliente que a criou. Uma aplicação sem franquia definida cria sessões limitadas apenas pela janela de ociosidade.
Um Servidor que encontra esta chave definida registra um Warning na inicialização e continua
iniciando, citando a chave e a tela Aplicações Cliente. Qualquer valor gera o aviso, inclusive 0
e negativos, que antes recusavam a inicialização. Uma chave sem valor (null no JSON, ou uma variável
de ambiente vazia ou em branco) não define nada e não gera aviso.
Atualizando uma implantação que a definia. A partir da 1.17.0, as sessões dela ficam sem limite até
um Administrador definir a franquia em cada Aplicação Cliente que precisa de uma, porque nenhuma
Aplicação Cliente tem franquia depois da atualização e nada traz o valor da chave para elas. Logo depois
de atualizar, defina a franquia nessas aplicações (1 para um integrador que pediu sessões de uso
único) e então remova a chave.
O que a franquia de uma Aplicação Cliente significa: quantas chamadas de assinatura uma sessão pode fazer antes de terminar como Esgotada (Exhausted), o que vier primeiro entre seus dois limites. Uma unidade por chamada, não por documento: um lote de cinquenta gasta uma, e uma chamada cujos documentos falharam todos antes de o certificado assinar não gasta nenhuma. Zero ou menos é recusado na tela. É concedida na criação, então alterar a franquia de uma aplicação só governa as sessões que ela criar depois. O protocolo não informa o saldo restante; a tela Sessões de Assinatura mostra o quanto foi gasto.
A superfície de assinatura
environment:
Signing__RequestBudget: "00:01:00"
Signing__AuthorizationTimeout: "00:01:00"
Signing__MaxPendingAuthorizations: "2"
Signing__HashSignTimeout: "00:00:25"
Signing__SignerCancelBudget: "00:00:03"
Signing__StrandedAfter: "00:10:00"
Signing__StrandedSweepInterval: "00:05:00"
Signing__WorkstationReconnectGrace: "00:00:15"
Signing__ReconnectPollInterval: "00:00:00.250"
Signing__MaxDocumentBytes: "10485760"
Signing__TransportHeadroomBytes: "65536"
Signing__MaxBatchItems: "50"
Signing__SignerConcurrency: "32"
| Chave | Padrão | Override | Significado |
|---|---|---|---|
Signing:RequestBudget | 60 s | não | Toda uma assinatura síncrona, da admissão da requisição até os bytes assinados, ou, numa sessão com PIN por transação "workstation", a partir do momento em que o titular responde ao pedido. Uma chamada de Assinatura de hash é limitada por ele como um todo. Estourar esse prazo responde SIGN_TIMEOUT. HashSignTimeout mais WorkstationReconnectGrace precisam caber nele, ou a inicialização é recusada. Um documento assinado com o REST PKI Core recebe um limite próprio para a conclusão depois que a chave assinou: veja REST PKI Core. |
Signing:AuthorizationTimeout | 60 s | não | Quanto tempo uma chamada de assinatura numa sessão com PIN por transação "workstation" espera o titular responder à Autorização de assinatura no Tray App (uma vez por chamada, inclusive num lote). Sem resposta, a chamada recebe 422 PIN_NOT_AVAILABLE (timed out) e nada é assinado. Ele corre fora de RequestBudget, então o tempo que uma pessoa gasta lendo e digitando nunca vira SIGN_TIMEOUT. Um valor não positivo, ou acima de dez minutos, recusa a inicialização: uma estação de trabalho recusa uma janela de pedido mais longa. Veja abaixo. |
Signing:MaxPendingAuthorizations | 2 | não | Quantas chamadas com PIN por transação podem esperar o titular numa mesma máquina ao mesmo tempo: por padrão, um pedido na tela e um na fila. Mais uma é respondida na hora com 422 PIN_NOT_AVAILABLE (too many calls waiting), e nada é assinado nem mostrado. Chamadas feitas uma depois da outra nunca são recusadas por ele. Abaixo de 1 ou acima de 8, recusa a inicialização. |
Signing:HashSignTimeout | 25 s | não | Quanto tempo uma assinatura de hash despachada pode levar antes de a máquina ser considerada inacessível. Bem acima dos cerca de 340 ms que um token gasta, porque a máquina pode estar ocupada com o documento de outra pessoa. |
Signing:SignerCancelBudget | 3 s | não | Quanto tempo a limpeza pode levar quando uma execução que não assinou nada encerra o documento no Signer. |
Signing:StrandedAfter | 10 min | não | Quanto tempo uma Operação de Assinatura pode ficar Pendente antes de a varredura encerrá-la como Com falha, com RUN_STRANDED. Precisa ser maior que o dobro de RequestBudget mais SignerCancelBudget, ou a inicialização é recusada: o dobro desde o Servidor 1.18.0, porque um documento assinado com o REST PKI Core recebe, depois que a chave assinou, um limite para a conclusão do mesmo tamanho do prazo. Uma implantação que a definiu entre o piso antigo (uma vez o prazo) e o novo se recusa a iniciar, citando a chave; os padrões atendem à regra. AuthorizationTimeout fica de fora da regra de propósito: o registro de um documento só é aberto depois que a chamada dele é autorizada. Uma execução no REST PKI Core que a varredura encerra depois de a conclusão ter começado também gera uma linha Error, porque o REST PKI Core pode guardar para ela um documento assinado que nenhuma Operação de Assinatura cita. |
Signing:StrandedSweepInterval | 5 min | não | A frequência dessa varredura. Uma passagem também roda na inicialização. Não é validada na inicialização. |
Signing:WorkstationReconnectGrace | 15 s | sim | Quanto tempo uma assinatura espera a estação de trabalho vinculada voltar antes de responder WORKSTATION_OFFLINE. Numa sessão com PIN por transação "workstation", a mesma tolerância é dada mais uma vez, antes de o titular ser consultado. Zero recusa na hora e é válido; um valor negativo recusa a inicialização. |
Signing:ReconnectPollInterval | 250 ms | não | A frequência com que essa tolerância verifica de novo a presença. Um valor não positivo recusa a inicialização. |
Signing:MaxDocumentBytes | 10 MB (10485760) | não | O maior documento que o Servidor assina, medido nos bytes decodificados. Acima do limite, responde 413 no envelope do contrato. Limita a memória, não o armazenamento. Os limites de transporte subjacentes são derivados dele. |
Signing:TransportHeadroomBytes | 64 KB | não | Folga, além do documento codificado, para o restante do corpo da requisição. |
Signing:MaxBatchItems | 50 | não | Quantos documentos uma chamada em lote pode citar, e quantos hashes uma chamada de Assinatura de hash pode trazer. Uma chamada com mais é recusada antes de qualquer item ser assinado. Junto com MaxDocumentBytes, define o que um lote em andamento pode ocupar: 500 MB com os padrões. Na Assinatura de hash, é quantas vezes uma chamada pode usar a chave do titular, então aumentá-lo para os lotes aumenta isso também. |
Signing:SignerConcurrency | 32 | não | Quantas execuções de assinatura podem estar em andamento no serviço de assinatura ao mesmo tempo, em todo o Servidor. Um documento assinado com o REST PKI Core ocupa uma vaga, como um assinado pelo Signer. Um lote maior roda em ondas. Zero recusa a inicialização. A Assinatura de hash não passa por ele, porque não conversa com nenhum serviço de assinatura. |
Todas exigem reinício, exceto WorkstationReconnectGrace.
Chamadas esperando o titular
Numa sessão com PIN por transação "workstation", uma chamada pode levar WorkstationReconnectGrace,
depois AuthorizationTimeout e depois RequestBudget. A máquina é informada dos dois últimos e guarda
o PIN que recebeu por no máximo a soma dos dois (contando no máximo uma hora de RequestBudget). Uma
implantação cujos titulares digitam devagar aumenta AuthorizationTimeout, e nada mais muda com isso.
Uma chamada esperando o titular mantém a vaga dela no throttling global
(Throttle:ConcurrencyLimit) o tempo todo, pedido incluído. Muitos titulares
deixando pedidos sem resposta ao mesmo tempo ocupam esse limite mais rápido do que as assinaturas,
então uma implantação que ativa o PIN por transação para uma Aplicação Cliente movimentada conta essas
chamadas contra ele, e não contra SignerConcurrency, que elas só alcançam depois que o titular
responde. MaxPendingAuthorizations limita quantas uma máquina pode reter, então o máximo que uma
frota pode reter é essa quantidade por máquina, por mais chamadas que um cliente dispare.
O throttling global
Um limite para quantas chamadas do contrato o Servidor executa ao mesmo tempo, com uma fila curta à
frente dele. Uma chamada descartada responde 429 SERVER_BUSY, sem Retry-After. Ele vale somente
para a superfície do SignSession Contract; o canal das estações de trabalho, o console administrativo,
o probe de saúde, a página inicial, a documentação, a admissão de estações de trabalho e os downloads
de Versões da Estação de Trabalho ficam fora dele (os downloads têm
um limite próprio).
Os padrões ficam quase sete vezes acima da carga projetada: é um disjuntor (circuit breaker), não um
teto de vazão.
| Chave | Padrão | Significado |
|---|---|---|
Throttle:ConcurrencyLimit | 200 | Quantas chamadas do contrato podem rodar ao mesmo tempo. Uma chamada ocupa a vaga enquanto a requisição dela durar, o que, numa sessão com PIN por transação, inclui o tempo que o titular leva no pedido. Zero recusa a inicialização; de propósito, não há como desligá-lo. É Signing:SignerConcurrency, e não este, que molda a vazão de assinaturas. |
Throttle:QueueLimit | 50 | Quantas chamadas podem esperar por uma vaga antes de a seguinte ser descartada. Zero é válido e significa sem fila; um valor negativo recusa a inicialização. |
Diagnóstico de tempos
Diagnostics:ServerTiming
Padrão false · Override pelo Administrador não · Exige reinício sim
Se toda resposta do SignSession Contract traz um header
Server-Timing que divide a chamada nas etapas que ela
alcançou: gate (a espera por uma vaga de Signing:SignerConcurrency), um valor signer-… por
chamada ao Signer (ou um valor rest-pki-core-… por chamada ao REST PKI Core, para um documento que uma
Aplicação Cliente assina com o REST PKI Core), workstation (a ida e volta até a
máquina), as etapas ws-… da própria máquina e o total da chamada. Cada etapa vem em milissegundos, somada ao longo da chamada,
com a contagem ao lado. Uma etapa que a chamada não alcançou fica de fora. Uma chamada descartada pelo
throttling e um 401 não trazem o header.
Server-Timing: gate;dur=0.1;desc="n=1", signer-upload;dur=212.4;desc="n=1", …, workstation;dur=402.7;desc="n=1", total;dur=1203.7
Serve para medir uma implantação, por exemplo com um teste de carga, e fica desligado em produção: o header vai para todo chamador que tem uma chave de API, então informa a toda Aplicação Cliente quanto tempo levam o serviço de assinatura e os tokens desta implantação, e quais sessões assinam numa estação de trabalho em vez de no Cofre de Certificados.
Desde o Servidor 1.17.0, ele decide apenas se o header é enviado. Desligá-lo esconde as etapas, mas
não impede que elas sejam medidas. O Servidor mede toda chamada de assinatura, qualquer que seja este
valor, e grava as etapas nos details das linhas da Trilha de Auditoria que grava de qualquer forma
(signing.completed ou signing.failed para um documento, hash-signing.completed ou
hash-signing.failed para uma chamada de Assinatura de hash), como um membro timing e, quando a
máquina informou um, um membro machineReported. Essas linhas são lidas por administradores, nunca por
uma Aplicação Cliente, e os tempos do Painel vêm delas.
environment:
Diagnostics__ServerTiming: "true"
Admissão de estações de trabalho
Quais máquinas podem pedir para entrar, quanto da fila um desconhecido pode ocupar e por quanto tempo um pedido abandonado permanece. Uma implantação padrão não define nenhuma destas. Todas exigem reinício, e nenhuma está na tela Configurações e usuários.
environment:
Admission__InstallerKeys__0: "MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE…"
Admission__MaxPending: "500"
Admission__RequestsPerAddress: "300"
Admission__RequestWindow: "00:01:00"
Admission__PendingExpiry: "7.00:00:00"
Admission__RequireHardwareBackedKeys: "false"
| Chave | Padrão | Significado |
|---|---|---|
Admission:InstallerKeys | A Installer Key distribuída com o TrustBridge | As Installer Keys com que este Servidor aceita pedidos de admissão assinados, cada uma um SubjectPublicKeyInfo DER em base64 de uma chave pública ECDSA P-256. Definir esta chave substitui o padrão, em vez de somar a ele. Liste duas durante uma troca: adicione a nova ao lado da antiga, atualize a frota e então remova a entrada antiga. Um valor que não pode ser interpretado recusa a inicialização. |
Admission:MaxPending | 500 | Quantas máquinas podem estar aguardando um Administrador ao mesmo tempo. Acima disso, o pedido de uma máquina que este Servidor nunca viu é recusado. Zero recusa a inicialização. |
Admission:RequestsPerAddress | 300 | Quantos pedidos de admissão um endereço de origem pode fazer por janela, com um endereço IPv6 contado pelo seu /64. É um limite contra incômodo: atrás de NAT, um escritório inteiro é um único endereço, e atrás de um proxy reverso a frota inteira conta como o proxy, a menos que ForwardedHeaders:TrustedProxies o cite. |
Admission:RequestWindow | 1 min | A janela fixa do limite acima. |
Admission:PendingExpiry | 7 dias | Quanto tempo o pedido de uma máquina fica na fila depois da última vez que o Servidor teve notícias dela. É contado a partir do último pedido, então uma máquina que continua pedindo nunca expira. A expiração não é uma recusa. |
Admission:RequireHardwareBackedKeys | false | Se a admissão de uma máquina cuja Chave da Estação de Trabalho não está em hardware deve ser recusada. Essa máquina continua aparecendo na fila, e a tela explica por que o controle Admitir a recusa. A postura é uma declaração da própria máquina; nada a atesta. |
O console administrativo
O primeiro Administrador, se uma senha sozinha dá acesso ao console, se um certificado dá, e se uma senha ainda dá acesso.
environment:
Admin__Bootstrap__Email: admin@example.com
Admin__Bootstrap__Password: ${ADMIN_BOOTSTRAP_PASSWORD}
Admin__Bootstrap__DisplayName: Platform Administrator
Admin__SecondFactor__Required: "true"
Admin__CertificateSignIn__Enabled: "false"
Admin__CertificateSignIn__WebPkiLicense: ${WEB_PKI_LICENSE}
Admin__CertificateSignIn__Required: "false"
Admin:Bootstrap:Email, Admin:Bootstrap:Password, Admin:Bootstrap:DisplayName
Padrão não definido · Override pelo Administrador não · Exige reinício sim
O primeiro Administrador. Lidas num Servidor cuja tabela de contas está vazia, e inertes em todas
as inicializações seguintes: uma senha configurada nunca recria uma conta excluída nem redefine uma
existente. A senha precisa atender às regras de senha da identidade, ou a conta não é criada e o motivo
é registrado no log. Remova as duas depois de entrar. Com elas não definidas e a tabela vazia, o
Servidor registra um Warning e não cria nada; ninguém consegue entrar no console até que algo
coloque uma conta lá.
Admin:SecondFactor:Required
Padrão true · Override pelo Administrador não, de propósito · Exige reinício sim
Se uma Conta Administrativa precisa apresentar um segundo fator além da senha. Configuração da implantação, e nunca uma tela: uma opção que desativa o segundo fator, ao alcance de dentro do console que ele protege, é uma opção que um invasor desliga no caminho. Uma linha salva no banco de dados com esta chave é ignorada. Vale para toda a plataforma, sem exceção por conta.
É também o acesso de emergência (break-glass) para um Administrador que perdeu o autenticador; o procedimento está em Segurança. A postura enfraquecida é anunciada a cada inicialização enquanto a opção estiver desligada.
Admin:CertificateSignIn:Enabled
Padrão false · Override pelo Administrador não, de propósito · Exige reinício sim
Se o console oferece o Acesso com Certificado, com um e-CPF ICP-Brasil. O certificado é escolhido numa
página própria, /admin/login/certificate, à qual um link da página de login leva, e é lido no
computador da própria pessoa pelo Lacuna Web PKI, uma extensão de navegador com uma parte nativa que
cada pessoa instala uma vez; só em navegadores de desktop. Num celular ou tablet, a página do
certificado avisa isso. Só certificados e-CPF são listados.
Desligada, a página de login não mostra nenhum sinal dela: nenhum link, nenhuma folha de estilo
própria e nenhum cookie, e quem abre a página do certificado por um favorito é mandado para a página de
login. Ligada, ela precisa de
Admin:CertificateSignIn:WebPkiLicense, ou o Servidor
recusa a inicialização citando essa chave. Ligada ou desligada, a própria página de login não traz
script nem licença; só a página do certificado traz. A página de login mantém o formulário de senha, a
menos que Admin:CertificateSignIn:Required o retire.
Ligada, a página de login abre na forma de entrar que o navegador usou por último (Servidor 1.20.0 e
posteriores). Uma senha ou um certificado aceitos, mesmo que depois venha a etapa do Segundo Fator,
gravam um cookie, TrustBridge.SignInCredential, restrito a /admin/login e mantido por um ano, que diz
qual foi. Ele não é uma credencial, não autoriza nada e sobrevive a uma saída. Um navegador cuja última
forma foi um certificado é mandado da página de login para a página do certificado, a menos que o
endereço cite uma recusa ou peça o formulário de senha (?usePassword=true); um seletor Senha |
Certificado digital nas duas páginas deixa a outra forma a um clique. Desligada de novo, o cookie não é
mais lido nem gravado.
Ligada, uma conta com CPF vinculado entra só com o certificado: sem senha e sem código do Segundo
Fator. Um Administrador digita o CPF de outra conta na tela de contas, ao criá-la ou com Definir CPF
vinculado na linha dela, e só enquanto esta chave está ligada; ninguém define o próprio, então
ninguém entra com certificado até outro Administrador ter definido um. Uma conta que ainda não tem
Segundo Fator, onde Admin:SecondFactor:Required está ligada, é levada a
cadastrar um primeiro.
A página do certificado pede um desafio em /admin/login/certificate/challenge, com limite de dez por
minuto por endereço de origem, e desiste de uma requisição depois de trinta segundos. Atrás de um
proxy reverso, cite-o em ForwardedHeaders:TrustedProxies, ou
todos os navegadores dividem os dez do proxy, e qualquer pessoa que consiga acessar a página do
certificado pode esgotá-los por um minuto de cada vez.
Uma linha salva no banco de dados com esta chave é ignorada, pelo motivo de Admin:SecondFactor:Required:
o que decide como uma pessoa chega ao console nunca é configurado de dentro dele.
Admin:CertificateSignIn:WebPkiLicense
Padrão não definido · Override pelo Administrador não · Exige reinício sim
Obrigatória quando Admin:CertificateSignIn:Enabled está ligada. A licença do Web PKI, no
formato de uma linha que a Lacuna emite, escrita como uma única string. Não o formato JSON: escrita
como objeto, não é lida por nada, e o Servidor recusa a inicialização como se nenhuma licença estivesse
definida. Não é a licença do PKI SDK (Certificates:Validation:License).
Não é um segredo. Ela é avaliada no navegador, então qualquer pessoa que carregue a página do certificado pode lê-la, e ela está vinculada aos domínios que cita. Ela precisa citar o hostname que as pessoas digitam: uma licença que não o cobre falha na primeira vez que o componente é usado, e a página do certificado informa isso como um problema de licença para o operador.
Admin:CertificateSignIn:Required
Padrão false · Override pelo Administrador não, de propósito · Exige reinício sim
Se as senhas estão desligadas para o console administrativo. Ligada, a página de login manda todo visitante para a página do certificado, uma senha enviada mesmo assim é recusada sem nada ser verificado nem contado contra a conta, e um certificado do CPF vinculado da conta é a única forma de entrar. O cadastro do Segundo Fator num primeiro acesso com certificado funciona como funciona sem ela.
Ela exige Admin:CertificateSignIn:Enabled ligada. Ligada enquanto aquela está desligada descreve
um console sem nenhuma forma de entrar, então o Servidor recusa a inicialização citando as duas chaves.
É a única inicialização que esta chave recusa.
Uma conta sem CPF vinculado não consegue entrar enquanto ela está ligada, seja Administrador ou Auditor. Outro Administrador define um na tela de contas, e as senhas continuam desligadas enquanto isso. Ninguém consegue definir o próprio, então um Administrador sozinho não consegue desligar as senhas: uma implantação que faz isso precisa de pelo menos dois Administradores, cada um com um CPF vinculado que o outro definiu, antes de ligar esta chave.
Ela avisa a cada inicialização enquanto está ligada. O aviso conta quantas contas habilitadas não
têm CPF vinculado, quantas delas são de Administradores e quantos Administradores habilitados existem.
Quando o segundo número chega ao terceiro, ninguém consegue administrar a plataforma. Onde nenhum proxy
é citado em ForwardedHeaders:TrustedProxies, o aviso também diz que todos os navegadores dividem os
dez desafios por minuto do proxy, então qualquer pessoa que consiga acessar a página do certificado consegue
deixar todo mundo de fora. Cite o proxy antes de ligar esta chave.
Ela é o acesso de emergência (break-glass). Quando ninguém consegue apresentar um certificado que o
Servidor aceite (uma Autoridade Certificadora Confiável removida, uma licença da PKI vencida, uma
licença do Web PKI que não cita mais o hostname, uma atualização de navegador que quebrou a extensão,
ou o CPF vinculado do último Administrador removido), defina-a como false e reinicie: o login com
senha volta sem nenhuma outra mudança. Ligue-a de novo depois; nada vai lembrar você, porque o aviso
só aparece enquanto as senhas estão desligadas.
Uma sessão aberta com senha antes da mudança não é encerrada por ela. Um login com senha que estava parado na etapa do código quando o Servidor reiniciou volta para o formulário de login.
A Trilha de Auditoria
Audit:RetentionDays
Padrão 365 · Override pelo Administrador sim · Exige reinício não
Por quanto tempo os eventos de auditoria são mantidos; uma limpeza diária exclui as linhas mais antigas. Abaixo de 1, a inicialização é recusada: uma retenção de zero apagaria toda a trilha na passagem seguinte.
A limpeza não toca na Atividade de assinatura, as contagens do Painel: elas não citam nenhum titular e são mantidas enquanto a instalação existir, então os números "desde a instalação" sobrevivem a esta retenção e vão divergir de uma contagem das linhas de auditoria que restam. Os dois estão certos.
A limpeza nunca exclui uma linha que a Atividade de assinatura ainda não contou. Na primeira inicialização de um Servidor com a 1.17.0 ou posterior, a Atividade de assinatura é preenchida a partir de toda a Trilha de Auditoria, um bloco de cada vez, e a limpeza não exclui nada até isso terminar; depois disso, ela nunca exclui além do ponto até o qual a contagem está consolidada. Num Servidor em funcionamento esse ponto fica cinco minutos atrás do momento atual, então isso não muda nada. Só importa quando a contagem parou, ou quando o Servidor ficou parado por mais tempo que a retenção, e então a limpeza registra um aviso dizendo onde está retida e se recupera quando a contagem se recuperar.
Não há configuração para o destino de uma gravação de auditoria que falhou. Uma entrada que o banco de
dados não aceita é gravada no Log do Servidor no nível Critical, com a própria linha, e o console
administrativo mostra um alerta. Ela chega até você pelo pipeline de logs que a implantação tiver,
então o fallback da auditoria faz parte da sua retenção de logs, e não dos seus backups.
O Painel
O calendário em que o Painel do console administrativo lê a Atividade de assinatura (Servidor 1.17.0 e posteriores). A Atividade de assinatura é contada a partir da Trilha de Auditoria um minuto de cada vez, cinco minutos atrás do momento atual, em blocos de uma hora em UTC; esta chave diz onde começam um dia e um mês quando essas horas são lidas de volta. O atraso e a cadência não são configuráveis.
environment:
Dashboard__TimeZone: America/Sao_Paulo
Dashboard:TimeZone
Padrão UTC · Override pelo Administrador não · Exige reinício sim
O fuso horário IANA cuja meia-noite começa um dia do Painel e cujo primeiro dia do mês começa um mês:
America/Sao_Paulo para uma implantação cujos operadores leem o dia no horário de Brasília, em que um
dia começa às 03:00 UTC. É o calendário da implantação, nunca o de quem lê. Um fuso que o Servidor não
encontra recusa a inicialização, citando esta chave, e o mesmo vale para um id de fuso do Windows como
E. South America Standard Time, cuja recusa indica o fuso IANA a escrever no lugar.
Lida uma vez, na inicialização. Alterá-la não recalcula nada: as mesmas horas em UTC são lidas em dias diferentes, então ela pode ser corrigida a qualquer momento. Num fuso cujo deslocamento não é um número inteiro de horas, a hora que contém a meia-noite conta no dia que ela começa.
Idiomas
environment:
Language__DefaultCulture: pt-BR
Language__SupportedCultures__0: en
Language__SupportedCultures__1: pt-BR
| Chave | Padrão | Significado |
|---|---|---|
Language:DefaultCulture | en | O idioma em que é respondida uma requisição sem um Accept-Language utilizável. Não é um idioma de toda a implantação: a preferência do navegador do leitor e o seletor de idioma prevalecem. Um valor fora do conjunto suportado, ou um erro de digitação, recusa a inicialização. |
Language:SupportedCultures | vazio, o que significa en e pt-BR | Todos os idiomas em que as páginas respondem. Informar um conjunto substitui o padrão. |
A superfície do contrato, os logs e a Trilha de Auditoria ficam permanentemente em inglês.
A documentação publicada
Documentation:ApiReferenceEnabled
Padrão true · Override pelo Administrador não · Exige reinício sim
Se a referência navegável é servida em /scalar. O documento legível por máquina em
/openapi/v1.json é o contrato de integração, é sempre servido e não é afetado. Os dois respondem sem
credencial.
A Assinatura de teste
Se a página inicial (Landing Page) permite que um visitante faça uma Assinatura de teste: uma assinatura de verdade, pelo contrato do próprio Servidor, pelo titular do certificado e pelo Lacuna Signer (ou pelo REST PKI Core, para uma chave cuja Aplicação Cliente assina os documentos com ele), num documento de uma página que o Servidor escreve sobre o certificado. É como um operador comprova, de um navegador, que uma implantação nova funciona de ponta a ponta, e como uma demonstração mostra o produto assinando. Desligada por padrão.
Um Administrador pode fazer uma de qualquer forma, pela página Assinatura de teste do próprio
console administrativo (/admin/test-signature, em Sistema), protegida pelo login administrativo e
pelo segundo fator dele. Um Auditor vê ali se a página pública está ligada, e nenhum formulário.
Desligada, a página pública não existe: /test-signature responde 404 e a página inicial é o que
era.
Ligada, a página inicial leva a /test-signature, em que quem pede digita um CPF, o PIN dele,
opcionalmente um CNPJ, a chave de API de uma Aplicação Cliente, opcionalmente um endereço de e-mail
alternativo, um tempo limite e quantos Documentos assinar. A execução é uma única requisição: uma
Sessão de Assinatura criada com essa chave, os dados do certificado, o documento, a assinatura dele e o
PDF assinado, e a sessão encerrada no final, tenha a execução dado certo ou não. Quem pediu recebe os
dados públicos do certificado e o PDF assinado, ou o que foi recusado, ou qual etapa falhou, com o
código de erro do contrato ao lado de uma falha na etapa da assinatura (Servidor 1.24.0). Nenhum id de
sessão ou de assinatura chega ao navegador.
Mais de um documento é uma única chamada em lote (Servidor 1.23.0): até 50, ou
Signing:MaxBatchItems onde ele for menor, assinados como cópias
numeradas da página numa única chamada POST /v1/signatures/batch, então com uma só cobrança da
Franquia de Assinaturas e, sob o PIN por transação, uma só confirmação no Tray App para todos. Os
documentos que foram assinados voltam num único ZIP, test-signatures.zip, e cada um que não foi
aparece ao lado, com a etapa em que falhou; a execução conta como concluída se pelo menos um foi assinado. Um tempo limite que se
esgota enquanto as cópias assinadas são baixadas mantém as que já tinham sido baixadas. Uma execução de
um documento é a mesma chamada única de sempre.
- A chave é de quem pede, e o Servidor não guarda nenhuma. Toda chamada da execução passa pela
verificação da chave de API, pelo throttling global e pela Trilha de Auditoria como a Aplicação
Cliente dessa chave, exatamente como a chamada de um integrador. Então uma demonstração começa
entregando uma chave a alguém, e quem a tem poderia usá-la direto contra o contrato. A página
devolve todos os campos preenchidos na página que responde ao formulário, a chave de API e o PIN
inclusive, para que Assinar de novo seja um só clique (Servidor 1.23.0). Essa página é enviada
com
no-store, e uma demonstração numa máquina compartilhada termina fechando a aba. O Servidor não registra no log nem a chave nem o PIN, e esquece os dois assim que essa página é escrita. - Qualquer CPF pode ser tentado, e uma execução substitui uma Sessão de Assinatura já ativa para o mesmo CPF e CNPJ, como faria a criação de uma sessão com essa chave a partir de qualquer cliente; a página avisa isso ao lado do formulário. Um PIN errado conta para o bloqueio do titular. Uma execução por CPF de cada vez.
- Uma chave cuja Aplicação Cliente tem o PIN por transação ativado
funciona: numa sessão
"workstation", a execução espera o titular no Tray App dentro do tempo limite dela. - Cada execução grava
test_signature.completed,test_signature.failed(com a etapa) outest_signature.refused(com o motivo) na Trilha de Auditoria, com o endereço de quem pediu, o CPF e o CNPJ e a Aplicação Cliente da chave, e, num lote, quantos documentos foram pedidos e, se ele foi concluído, quantos foram assinados. Nunca o PIN nem a chave. - A página não precisa de rota para a internet.
environment:
TestSignature__Enabled: "true"
TestSignature__MaxTimeout: "00:02:00"
| Chave | Padrão | Override | Significado |
|---|---|---|---|
TestSignature:Enabled | false | não, de propósito | Se a página inicial oferece uma Assinatura de teste. Governa só a página pública. Configuração da implantação, e nunca uma tela: ela coloca um formulário de assinatura na raiz do host, e uma linha salva no banco de dados com esta chave é ignorada. |
TestSignature:MaxTimeout | 2 min | não | O maior tempo limite que quem pede pode digitar, e o valor com que o formulário começa. O tempo limite digitado limita a execução inteira e é a duração da sessão que ela cria. Um valor digitado acima deste é recusado, e não reduzido. Abaixo de um segundo ou acima de uma hora, recusa a inicialização. |
TestSignature:LoopbackAddress | não definido (onde o Servidor escuta) | não | Por onde uma execução acessa o /v1 do próprio Servidor. Não definida, é um endereço em que o Servidor escuta, HTTP simples antes de HTTPS, com um binding curinga como http://+:8080 lido como http://localhost:8080. Definida, é um endereço http ou https absoluto; qualquer outra coisa recusa a inicialização. |
As três exigem reinício, e MaxTimeout e LoopbackAddress são verificadas na inicialização mesmo
com Enabled desligada, porque a página administrativa as usa.
Mantenha MaxTimeout abaixo do timeout de leitura do seu proxy reverso. Uma execução é uma única
requisição HTTP mantida aberta até o documento assinado voltar, e um proxy que para de esperar a
interrompe. O front-end do App Service encerra uma requisição depois de 230 segundos; o
proxy_read_timeout do nginx é de 60 segundos, a menos que seja aumentado; o proxy da Cloudflare
responde 524 aos 100 segundos. Deixe folga para o titular responder a um pedido do Tray App, para o
serviço de assinatura, e 15 segundos além do valor para a execução encerrar a sessão. Atrás do padrão do nginx ou da
Cloudflare, o padrão de dois minutos é longo demais. A própria página para de esperar um minuto depois
do tempo limite digitado, ou com Esc, e traz o formulário de volta como ele foi enviado.
Para onde vai o loopback:
- O App Service escuta em HTTP simples atrás do TLS da plataforma, então o padrão está certo.
- O cenário Docker escuta só em HTTPS (
https://+:8443), com um certificado emitido para o nome que os visitantes digitam, que não élocalhost, então o padrão falharia em toda execução, inclusive nas da página administrativa. Acrescente um listener HTTP simples ligado ao loopback do próprio container,ASPNETCORE_URLS: https://+:8443;http://localhost:8080, e o padrão o escolhe. Nada fora do container consegue acessá-lo, e o arquivo do Compose publica só a 8443. Uma implantação atrás do seu próprio proxy já escuta em HTTP simples e não precisa de nada. - Qualquer que seja o host que o loopback chama,
AllowedHostsprecisa admiti-lo.
Atualizando a partir do Servidor 1.14.x: TestSignature:Cpfs, ApiKey, FallbackEmail,
Turnstile:SiteKey, Turnstile:SecretKey e Timeout não são mais lidas (quem pede digita o que elas
forneciam, não há verificação do Cloudflare Turnstile, e Timeout agora é MaxTimeout). Um Servidor
que encontra alguma delas definida registra um único Warning citando-as e inicia. Remova-as e
revogue a chave que ApiKey guardava na tela Aplicações Cliente: ela continua sendo uma chave
válida da Aplicação Cliente dela.
O canal das estações de trabalho
Como uma máquina admitida prova que é ela mesma a cada conexão, com uma asserção de curta duração
assinada pela Chave da Estação de Trabalho, e por quanto tempo o Servidor espera ter notícias de uma
máquina conectada. As duas chaves da asserção não são algo que uma implantação saudável precise mexer;
ClientTimeout é para mudar uma vez, depois que a frota estiver atualizada.
environment:
Workstations__ClockSkewTolerance: "00:01:00"
Workstations__MaxAssertionLifetime: "00:05:00"
Workstations__ClientTimeout: "00:00:30"
| Chave | Padrão | Significado |
|---|---|---|
Workstations:ClockSkewTolerance | 60 s | A diferença máxima entre o relógio do Servidor e o de uma estação de trabalho antes que essa máquina não consiga se conectar. Aplicada nas duas pontas. O log do Servidor cita a máquina com o relógio desviado e a diferença, positiva quando a máquina está atrás do Servidor (A workstation assertion was refused: Expired ou NotYetValid). Um valor negativo ou acima de uma hora recusa a inicialização. |
Workstations:MaxAssertionLifetime | 5 min | A maior janela de validade aceita numa asserção; uma declaração mais longa é recusada. Limita o cache de nonces, que guarda no máximo 100.000 nonces e, quando cheio, recusa em vez de esquecer. Um valor não positivo ou acima de uma hora recusa a inicialização. |
Workstations:ClientTimeout | 30 s | Por quanto tempo uma máquina conectada pode ficar em silêncio antes de o Servidor desligar a conexão dela. Veja abaixo. |
Todas exigem reinício, e nenhuma aceita override.
Workstations:ClientTimeout
Padrão 30 s (00:00:30) · Override pelo Administrador não · Exige reinício sim
Por quanto tempo uma estação de trabalho pode ficar sem que o Servidor tenha notícias dela, uma chamada ou um ping de keep-alive, antes de o Servidor fechar a conexão. A máquina então aparece offline na página da frota na próxima atualização (em até 10 s), o último contato dela é gravado e a desconexão entra na Trilha de Auditoria. Uma máquina que continua lá se reconecta sozinha. Isso só importa para máquinas que somem: um cabo desconectado, Wi-Fi perdido, a tampa de um notebook fechada, um firewall que derruba a conexão em silêncio. Uma máquina que desliga ou para o Service de forma limpa aparece offline na próxima atualização, qualquer que seja este valor.
Defina-a como 00:00:15 quando todas as máquinas rodarem uma release do Workstation
posterior à 1.1.0, e não antes. O Servidor e um Workstation Service atual fazem ping a cada 5 s; o
Workstation 1.0.x e o 1.1.0 fazem ping a cada 15 s, e nada que o Servidor diga muda isso.
Limitadas a 15 s, essas máquinas seriam desconectadas depois de quase todo ping, e cada desconexão é
uma reconexão, um handshake e um par de conexão/desconexão na Trilha de Auditoria. A coluna Versão do serviço
da página da frota é onde verificar. Cada máquina para a qual o valor é curto demais é citada no log do
Servidor em Warning, uma vez por conexão: procure
pings every 00:00:15, but Workstations:ClientTimeout is.
Com 15 s, uma máquina que some aparece offline em cerca de 25 s; com o padrão, em cerca de 40 s. Uma máquina em long polling (atrás de um proxy que recusa WebSockets, por exemplo) não é desconectada por este timeout: ela nunca faz ping, e a conexão termina pelo timeout de ociosidade da própria camada de conexão quando as requisições de polling param.
Uma linha de desconexão na Trilha de Auditoria diz o motivo, como "reason" nos detalhes: timed-out
para este timeout, closed, revoked, removed, returned-to-queue, server-stopping ou error. A
aba Eventos da máquina na página da frota mostra a mesma palavra, exceto removed: uma máquina
removida não tem painel, então a última desconexão dela é lida na Trilha de Auditoria, pelo id da
máquina. Uma máquina em long polling que ficou em silêncio aparece como closed, por isso a linha
também cita o transport dela.
Escreva no formato hh:mm:ss. Um 15 sozinho vira quinze dias, e 0:15, quinze minutos.
Menos de 10 s (o dobro dos 5 s em que uma máquina atual faz ping) ou mais de 5 minutos recusa a
inicialização.
Atualizar um Servidor e sua frota para o protocolo 6
O canal está no protocolo 6 (Servidor 1.15.0, Workstation 1.6.0), que acrescenta a Autorização de assinatura: numa sessão criada por uma Aplicação Cliente com o PIN por transação ativado, o Servidor pede ao Tray App da máquina vinculada o PIN de cada chamada de assinatura. A janela deste Servidor é 5–6. Do Workstation 1.7.0 ao 1.10.0, todos continuam no protocolo 6.
| Máquina | Protocolo | Com o Servidor 1.15.0 ou posterior |
|---|---|---|
| Workstation 1.6.0 a 1.10.0 | 6 | Totalmente suportada. Entregue o Workstation 1.8.0 e posteriores com o Servidor 1.20.0 ou posterior, o primeiro cujo canal das estações de trabalho aceita o Relatório da Estação de Trabalho deles: um anterior encerra a conexão de um relatório do 1.8.0 acima de 32 KB, enquanto o 1.8.1 e posteriores mantêm os relatórios abaixo de 32 KB até o Servidor aceitar um, e continuam conectados. O console que o Workstation 1.10.0 informa aparece a partir do Servidor 1.23.0. |
| Workstation 1.5.0 | 5 | Conecta e atende todas as sessões como antes. Ela nunca recebe uma Autorização de assinatura, então, para uma sessão criada por uma Aplicação Cliente com o PIN por transação ativado, conta como offline: um titular nessa situação cujas máquinas estão todas no protocolo 5 recebe 422 WORKSTATION_OFFLINE, e o Servidor registra um Warning citando a máquina e o protocolo dela cada vez que a deixa de lado. |
| Workstation 1.4.x e anteriores | 4 ou menos | Recusada no handshake, com Atualização necessária na linha dela na frota e na Trilha de Auditoria. Ela também não pode receber oferta de versão: atualize-a manualmente ou por Política de Grupo. |
Antes de atualizar o Servidor, confira na página da frota se alguma máquina admitida ainda está no
1.4.x, e atualize-a primeiro para o Workstation 1.5.0. Depois atualize o Servidor, faça o upload de uma
release no protocolo 6 e deixe a frota recebê-la. Ative o PIN por transação para uma Aplicação Cliente
só quando as máquinas dos titulares dela rodarem o 1.6.0 ou posterior. Uma máquina no protocolo 6 não consegue se
conectar a um Servidor anterior ao 1.15.0 (janela 4–5): ela recebe update the Server first, não
recebe licença, e todo certificado aparece como UNTRUSTED no Tray App até o Servidor ser atualizado.
O que muda para os integradores: nada, a menos que a Aplicação Cliente deles tenha o PIN por transação ativado. O protocolo é do canal, não do contrato.
Atualizar um Servidor e sua frota para o protocolo 5
Substituída num aspecto pelo protocolo 6, acima: um Servidor a partir do 1.15.0 tem a janela 5–6, então a máquina no protocolo 4 que esta seção descreve como conectando é recusada. O resto é como o protocolo 5 chegou.
O protocolo 5 (Servidor 1.13.0, Workstation 1.5.0) é a versão em que o Servidor deixa de enviar o PIN da aplicação cliente a qualquer estação de trabalho. A criação de sessão desafia cada máquina candidata com um nonce, a máquina responde com uma Prova de PIN (PIN Proof) sobre o PIN que tem em cache (ou, para um Certificado A1, sobre o verificador do PIN do Certificado A1), e o Servidor decide se correspondeu. Os Servidores 1.13.0 a 1.14.1 têm a janela 4–5.
| Máquina | Protocolo | Com o Servidor 1.13.0 a 1.14.1 |
|---|---|---|
| Workstation 1.5.0 | 5 | Totalmente suportada. |
| Workstation 1.4.x | 4 | Conecta, é licenciada, assina para as sessões já vinculadas a ela e pode receber a oferta de uma versão. Ela nunca recebe desafio de PIN nem pedido de PIN, então, para a criação de sessão, conta como offline: um titular cujas máquinas estão todas no protocolo 4 recebe 422 WORKSTATION_OFFLINE, e o Servidor registra um Warning citando a máquina cada vez que a deixa de lado. |
| Workstation 1.0.x a 1.3.0 | 2 ou 3 | Recusada no handshake, com Atualização necessária na linha dela na frota e na Trilha de Auditoria. Ela também não pode receber oferta de versão: atualize-a manualmente ou por Política de Grupo. |
Essa atualização não seguiu "primeiro o Servidor, a frota dentro de uma versão". Uma máquina no protocolo 4 não atende novas sessões até ser atualizada, então o Servidor e a frota foram atualizados juntos: o upload do Workstation 1.5.0 foi feito na tela Versões da Estação de Trabalho como parte da atualização do Servidor, e a versão foi oferecida na hora. Uma máquina no protocolo 5 não consegue se conectar a um Servidor anterior ao 1.13.0 (janela 3–4).
O que muda para os integradores: nada. O PIN continua chegando em POST /v1/sessions e não vai
além do Servidor. INVALID_PIN agora significa que todas as candidatas deram uma prova e nenhuma
conferiu com o PIN enviado.
Atualizar um Servidor e sua frota para o protocolo 4
O protocolo 4 (Servidor 1.9.0, Workstation 1.4.0) é a versão em que o Servidor diz a uma
máquina qual Versão da Estação de Trabalho lhe é oferecida, então as atualizações entregues pelo
Servidor precisam dele nas duas pontas. Em todo handshake, uma máquina no protocolo 4 ou posterior
informa ao Servidor se a Política de Grupo desligou as atualizações entregues pelo Servidor, o Publisher Pin
com que o Service dela foi gerado e como terminou a última atualização. O Servidor mostra as três
informações na linha da máquina e grava workstation.update-installed, workstation.update-failed ou
workstation.update-refused na Trilha de Auditoria quando o resultado informado muda.
Uma oferta só alcança uma máquina Admitida abaixo da versão, cujo Publisher Pin liste o assinante da versão e cuja política deixe as atualizações ligadas. Oferecer de novo a uma máquina a versão que ela já tem é a forma de tentar outra vez depois de uma instalação que falhou, porque uma máquina nunca tenta de novo sozinha. Uma versão oferecida a qualquer máquina não pode ser excluída até as ofertas serem retiradas. As telas estão descritas em Console administrativo.
Downloads de Versões da Estação de Trabalho
Como o Servidor entrega a uma máquina a Versão da Estação de Trabalho que lhe foi oferecida. Uma versão oferecida a todas as máquinas são até 500 máquinas × cerca de 100 MB vindos de um único Servidor, então a única chave daqui serve para evitar um estouro de downloads simultâneos. Uma implantação padrão não a define.
Uma máquina baixa de GET /workstations/releases/{version}. Toda requisição, tanto uma faixa retomada
quanto a primeira, traz uma asserção nova assinada pela Chave da Estação de Trabalho e só é atendida
enquanto o Servidor oferece aquela versão àquela máquina, então retirar uma oferta interrompe um
download na requisição seguinte. Toda recusa responde o mesmo 401; o log do Servidor diz qual
verificação falhou (A Workstation Release download was refused). Os downloads ficam fora do
throttling global e não gravam linha própria na Trilha de Auditoria; a trilha
registra o que cada máquina fez depois com o arquivo.
Um download é servido da cópia em /tmp/trustbridge-releases, recriada a partir do banco de dados
quando falta, ou lida direto do banco onde esse diretório não pode ser gravado, o que o Servidor
registra uma vez em Warning.
environment:
WorkstationReleases__MaxConcurrentDownloads: "20"
WorkstationReleases:MaxConcurrentDownloads
Padrão 20 · Override pelo Administrador não · Exige reinício sim
Quantos downloads de versões o Servidor envia ao mesmo tempo. Um download ocupa a vaga enquanto a
requisição dele durar. Um acima do limite recebe 503 com Retry-After, nunca o 429 SERVER_BUSY
do contrato, com uma espera sorteada de novo entre 30 e 90 segundos, para que máquinas recusadas juntas
não voltem juntas. Cada máquina também espera um atraso aleatório de até dez minutos antes de começar,
o que espalha a maior parte de uma distribuição antes de este limite ser atingido.
Aumente-o para um Servidor com um link rápido cuja frota deva se atualizar mais cedo; reduza-o onde o link é compartilhado com tráfego de assinatura que não pode esperar. Zero ou negativo recusa a inicialização.
Relatórios das Estações de Trabalho
O que o Servidor guarda do Relatório da Estação de Trabalho que cada máquina envia por conta própria (Servidor 1.20.0 e posteriores; o Workstation 1.8.0 é a primeira release que envia um). Cada informação de um relatório substitui a anterior, então só os erros precisam de retenção: um grupo por máquina, origem, categoria de log e modelo de mensagem, com uma contagem acumulada, mantido até a máquina passar um tempo sem informá-lo. Eles nunca são gravados na Trilha de Auditoria. Uma implantação padrão não a define.
O Servidor também guarda o console de cada máquina (Servidor 1.23.0, de máquinas no Workstation 1.10.0 ou posterior): a Conta no console, se a sessão do console está bloqueada, se um Tray App roda ali e a versão dele, e quantas outras sessões têm um, como o último relatório disse. Ele não precisa de retenção: é mantido para uma máquina desconectada ou revogada, vai embora com uma máquina removida, é apagado por um relatório que diz que o envio está desligado e nunca é gravado na Trilha de Auditoria.
environment:
WorkstationReports__ErrorRetentionDays: "30"
WorkstationReports:ErrorRetentionDays
Padrão 30 · Override pelo Administrador não · Exige reinício sim
Por quantos dias um grupo de erros de uma máquina é mantido depois que a máquina deixou de informá-lo. Uma varredura diária exclui os grupos a que nenhum relatório acrescentou nada há mais tempo que isso, pelo relógio deste Servidor, de modo que uma máquina com o relógio errado não perde os grupos antes da hora nem os mantém para sempre; um grupo que a máquina informa de novo é mantido, e a contagem continua. A contagem das linhas que uma máquina registrou além dos 100 tipos que um relatório lista segue a mesma regra. Uma máquina removida leva os grupos dela junto, qualquer que seja a idade deles. O chip N tipos de erro (24h) da página da frota conta só o último dia, qualquer que seja este valor, então reduzi-lo encurta o histórico do painel de detalhes e não muda nenhum chip.
Abaixo de 1, recusa a inicialização: a passagem seguinte excluiria todos os grupos de erros que a frota informou.
O Cofre de Certificados
environment:
Vault__Enabled: "true"
Vault__RevalidationInterval: "01:00:00"
Vault:Enabled
Padrão false · Override pelo Administrador não, de propósito · Exige reinício sim
Se o Cofre de Certificados existe neste Servidor, isto é, se ele pode guardar uma chave privada
própria. Desligado por padrão porque esse nível torna condicional a premissa fundadora da plataforma;
o operador decide ativá-lo. Uma linha salva no banco de dados com esta chave é ignorada, pelo mesmo
motivo de Admin:SecondFactor:Required. Ligá-lo dá à licença do PKI SDK, que toda implantação já
tem, uma segunda função (ler os Certificados do Cofre do próprio Servidor) e traz junto a trava do
cofre. Desligá-lo não exclui nada: as linhas permanecem, a revalidação para, e
os caminhos que as leriam respondem que este Servidor não tem chaveiro.
Vault:RevalidationInterval
Padrão 1 h · Override pelo Administrador não · Exige reinício sim
A frequência com que o Servidor verifica de novo o veredito do que o cofre guarda. Não é validada na
inicialização: um valor não positivo é informado no nível Critical, e o worker não roda.
Validação de certificados e licença do PKI SDK
O mesmo nome de seção que o Workstation Service lê, com duas chaves que só fazem sentido lá. A licença é obrigatória e carregada em toda inicialização, com ou sem cofre, porque é a licença com que toda a frota funciona. Só uma implantação com o cofre ligado resolve o conjunto de âncoras; os timeouts e a janela de tolerância são validados em toda inicialização, de qualquer forma.
environment:
Certificates__Validation__License: ${PKI_LICENSE}
Certificates__Validation__UseIcpBrasil: "true"
Certificates__Validation__UseMachineRootStore: "false"
Certificates__Validation__UseLacunaTestPki: "false"
Certificates__Validation__RevocationGraceWindow: "1.00:00:00"
Certificates__Validation__RevocationTimeout: "00:00:05"
Certificates__Validation__CheckTimeout: "00:00:30"
Certificates:Validation:License
Padrão não definido · Override pelo Administrador não · Exige reinício sim
Obrigatória em toda implantação, com ou sem Cofre de Certificados. O LacunaPkiLicense.config
inteiro que a Lacuna emite, codificado em base64 numa única linha, e não um caminho. A imagem não traz
licença, então uma renovação é uma alteração de configuração e um reinício, e não um novo build.
É a licença da frota, além da do Servidor. O Servidor entrega o valor, exatamente como está configurado, a toda estação de trabalho Admitida na resposta ao handshake dela; é assim que um Workstation Service instalado é licenciado, e não há licença a definir numa máquina. A máquina a guarda só em memória e a recebe de novo a cada conexão, então reiniciar o Servidor alcança a frota inteira: toda máquina conectada se reconecta e aplica o valor, e uma máquina que estava offline o recebe quando se conectar de novo. Uma máquina Pendente não recebe nada.
base64 -w0 LacunaPkiLicense.config
[Convert]::ToBase64String([IO.File]::ReadAllBytes("LacunaPkiLicense.config"))
| Estado | O que acontece |
|---|---|
| Ausente (não definida, vazia ou em branco) | O Servidor recusa a inicialização, citando esta chave. Verificado antes da etapa do schema, então um Servidor que vai recusar não migra o banco de dados antes. |
| Recusada (vencida, corrompida, não é base64, não é uma licença) | O Servidor inicia e registra uma linha Critical citando esta configuração, com uma linha Error dizendo o motivo quando ele é conhecido. Toda página administrativa mostra um banner dizendo que nem a frota nem o cofre conseguem assinar até a licença ser renovada. O valor continua sendo entregue à frota, e cada máquina que o recusa avisa em Critical. Com o cofre ligado, todos os Certificados do Cofre informam UNTRUSTED e as importações são recusadas de imediato. |
| Carregada | Uma linha na inicialização dizendo que o SDK está licenciado e pronto. |
Ela vence, e nada avisa antes dessa data. O primeiro aviso é a linha Critical e o banner, e a
essa altura nada assina, nem no cofre nem em nenhuma máquina. Renová-la é substituir este valor e
reiniciar o Servidor; não há caminho em tempo de execução, e um Administrador não pode sobrescrevê-la
pelo console. Coloque o vencimento dela no calendário que acompanha as renovações de certificados. O
SDK só lê uma licença a partir de um arquivo, então o valor é gravado em
/tmp/trustbridge-pki e excluído na mesma chamada; um sistema de arquivos somente leitura sem um
/tmp gravável não consegue carregar a licença.
As fontes de âncoras
| Chave | Padrão | Significado |
|---|---|---|
Certificates:Validation:UseIcpBrasil | true | Confiar nas raízes da ICP-Brasil que o PKI SDK traz: o conjunto de âncoras de produção, embutido, sem download. Desligar é uma decisão de confiança. |
Certificates:Validation:UseMachineRootStore | false | Confiar também no repositório de raízes da própria máquina. No Servidor, um container Linux, não faz nada; é uma opção da estação de trabalho. |
Certificates:Validation:UseLacunaTestPki | false | Confiar também na PKI de teste da Lacuna. Somente para desenvolvimento: a Lacuna publica as chaves privadas desses certificados de exemplo. Um Servidor com esta opção ligada registra Critical na inicialização e mostra um banner de aviso em todas as páginas administrativas. |
Certificates:Validation:UseServerTrustedCas | true | Uma opção da estação de trabalho. Inerte no Servidor. |
Certificates:Validation:TrustedRootPaths | vazio | Não é considerada no Servidor. Um Servidor que a encontra definida inicia mesmo assim e registra uma linha Critical citando a chave e a página administrativa que a substituiu. Em vez dela, adicione uma Autoridade Certificadora Confiável em /admin/trusted-cas. |
Duas linhas Critical descrevem um conjunto de âncoras que não ancora nada: nenhuma âncora, e âncoras
que são só intermediárias, sem raiz autoassinada, de modo que nenhuma cadeia consegue terminar. As duas
situações tornam todo certificado UNTRUSTED.
Os limites de revogação
| Chave | Padrão | Significado |
|---|---|---|
Certificates:Validation:RevocationGraceWindow | 24 h (1.00:00:00) | Por quanto tempo a última verificação de revogação bem-sucedida mantém um certificado ACTIVE enquanto a AC dele está inacessível; passado esse prazo, o certificado vira STALE. Esta é a decisão de confiança: exatamente por quanto tempo um certificado continua assinando depois que a AC parou de responder, revogado ou não. Zero é válido e é o mais rigoroso; um valor negativo recusa a inicialização. |
Certificates:Validation:RevocationTimeout | 5 s | Quanto tempo um download de LCR ou uma busca de emissor pode levar antes de a AC ser considerada inacessível. Também limita cada busca do percurso AIA da descoberta de Autoridades Certificadoras Confiáveis. Um valor não positivo recusa a inicialização. |
Certificates:Validation:CheckTimeout | 30 s | O limite externo de toda a verificação de um certificado, incluindo o fallback para OCSP do SDK, que não tem limite próprio. Zero espera indefinidamente e não é recusado. |
Configurações que não são chaves de appsettings
| Configuração | Pertence a | Onde |
|---|---|---|
ASPNETCORE_ENVIRONMENT | O framework | Não definida nos dois cenários, e não definida significa Production, o que mantém o appsettings.Development.json inerte. |
ASPNETCORE_URLS | Kestrel | https://+:8443 no Docker, somente HTTPS, ou https://+:8443;http://localhost:8080 para fazer Assinaturas de teste (veja A Assinatura de teste). http://+:8443 no Docker atrás de um proxy reverso que termina o TLS, sem as configurações Kestrel__Certificates__*. Não definida no App Service. |
Kestrel__Certificates__Default__Path / __Password | Kestrel | O certificado TLS do próprio Servidor no Docker. Nada a definir no App Service. |
WEBSITES_PORT | App Service | 8080. |
WEBSITES_CONTAINER_START_TIME_LIMIT | App Service | 1800, para que uma migração longa não seja encerrada e reiniciada em loop. |
ASPNETCORE_FORWARDEDHEADERS_ENABLED | O framework | true no App Service, ou toda linha de auditoria registra o front end da plataforma em vez de quem fez a chamada. Ela confia em quem se conectar, então um proxy que você opera é citado em ForwardedHeaders:TrustedProxies; definir as duas recusa a inicialização. |
APPLICATIONINSIGHTS_CONNECTION_STRING | App Service | Lida quando Logging:ApplicationInsights:ConnectionString não está definida. |
TMPDIR | O processo | Move os três diretórios temporários (trustbridge-pki, trustbridge-logs, trustbridge-releases). De propósito, não existe configuração do TrustBridge para isso. |