← Professional Cloud Security Engineer: controlos e evidência
18 / 18 · 135 MIN

Governance: aprovações, âmbito e cobertura da evidência

Interpretar mecanismos de aprovação, dependências de assinatura, migração, exceções e lacunas de evidência no handover APS.

1. Transformar uma afirmação de controlo em evidência

Uma equipa fictícia prepara a entrada em operação de um serviço de reconciliação de fundos. O projeto apresenta uma pasta cloud configurada, uma aprovação de mudança e um dashboard sem violações. APS tem de decidir se estes elementos sustentam as afirmações feitas no handover. O caso não descreve procedimentos internos do BNP Paribas. Também não estabelece uma obrigação legal: os requisitos usados nos exercícios são definidos para aprendizagem e devem ser substituídos pelos requisitos aprovados de um projeto real. Começa por escrever a afirmação com precisão: qual o recurso, qual o controlo, que revisão se pretende avaliar e durante que período. Acrescenta o tipo de evidência necessário. Se o requisito diz que um controlo funcionou entre as 09:00 e as 11:00, uma captura às 11:00 não demonstra automaticamente as duas horas anteriores. Uma decisão de permitir uma mudança pode existir mesmo quando a observação técnica desse período está incompleta. Cria uma matriz com requisito, objeto, ambiente, revisão, janela, observação, limitação e responsável. O responsável não precisa de produzir pessoalmente toda a evidência, mas deve saber quem a pode obter e o que ela demonstra. Num comité, esta matriz permite uma decisão explícita sobre lacunas. Evita uma célula verde que misture configuração pretendida, autorização e resultado observado. O objetivo é permitir que outra pessoa reconstrua a conclusão a partir dos mesmos registos, sem ter de adivinhar pressupostos omitidos.

2. Interpretar o mecanismo de aprovação efetivamente usado

Um pedido normal que exige aprovação manual continua sem conceder acesso enquanto está pendente. A equipa deve verificar esse contexto antes de interpretar silêncio como consentimento. No histórico, policy-approved identifica uma decisão por política e auto-approved identifica o mecanismo de acesso urgente documentado. Nenhum destes rótulos demonstra, por si só, que alguém do cliente reviu individualmente a ocorrência. Registar apenas aprovado perde informação que pode ser decisiva na revisão posterior. O modo Transparency permite observação sem a aprovação adicional pretendida no fluxo manual. Além disso, remover settings locais pode fazer prevalecer a configuração herdada. No caso fictício, o projeto documentou revisão manual, mas o operador encontrou outro modo efetivo. A ação correta começa por comparar intenção e configuração, identificar a origem da diferença e avaliar o impacto no requisito. Acrescentar emails ao formulário de notificações não resolve essa divergência de comportamento. Prepara uma tabela de ocorrências com identificador, mecanismo, recurso, justificação, janela e evidência disponível. Se a equipa usa um modo que simplifica apoio técnico, descreve a escolha e os seus limites no desenho aprovado. Se o requisito muda, conserva a decisão e a data a partir da qual se aplica. Não reclassifiques eventos anteriores como manuais para os fazer coincidir com o documento mais recente. A comunicação deve explicar qual a garantia demonstrada em cada período e onde falta confirmação do estado efetivo.

3. Acompanhar a identidade e a versão da chave de assinatura

A equipa decide usar uma chave de assinatura própria para os pedidos de Access Approval. O operador consegue consultar a chave e executar um teste com a sua identidade, mas o serviço apresenta um erro de assinatura. A investigação deve seguir a conta de serviço Access Approval e a versão configurada, incluindo a permissão para assinar. O sucesso do operador não representa uma prova de acesso dessa conta. Uma assinatura protege a integridade do pedido; não transforma o seu conteúdo numa decisão de negócio correta. No exercício de passagem de conhecimento, desenha a cadeia de dependências: configuração de aprovação, versão da chave, identidade que a utiliza e equipa responsável pelo seu ciclo de vida. Acrescenta quem recebe um erro fora de horas e onde encontra a evidência para o diagnosticar. Uma dependência criptográfica sem responsável operacional pode atrasar apoio técnico quando o serviço de negócio já está degradado. Define uma verificação de mudança que compare a configuração pretendida com a identidade observada e o resultado esperado. Não uses chaves ou dados reais no exercício. Uma simulação documental pode mostrar que o plano está incompleto, mas não demonstra que IAM está correto no ambiente. Antes de propor alterar permissões, identifica o recurso e a ação em falta. Evita resolver um problema de identidade atribuindo privilégios amplos a todas as pessoas da equipa. No handover, conserva o limite entre o ensaio local e a verificação efetiva que o responsável da plataforma ainda tem de realizar.

4. Correlacionar autorização e atividade observada

Um relatório afirma que um objeto foi lido às 14:10, mas a única referência anexada é um pedido aprovado até às 15:00. A aprovação estabelece uma possibilidade dentro do âmbito aplicável, não o instante de cada operação. Access Transparency fornece informação sobre ações de pessoal Google; essa evidência tem uma função diferente da decisão de autorização. Os registos de ações do cliente também podem ser necessários para reconstruir o incidente. Confirma sempre os serviços e o âmbito efetivamente cobertos pelas fontes consultadas. Para treinar a análise, cria três linhas fictícias: pedido recebido, decisão registada e ação observada. Mantém identificadores distintos. Pede ao colega que reconstrua a sequência sem usar o título do ticket como prova de uma leitura. Se o evento não puder ser correlacionado, marca a ligação como não demonstrada. Não inventes um evento a partir do intervalo de autorização nem concluas que um acesso foi indevido apenas porque a exportação fornecida está incompleta. No trabalho APS, a diferença aparece quando várias equipas pedem conclusões rápidas sobre uma intervenção do fornecedor. Explica o que os registos disponíveis provam e a próxima fonte necessária. Se falta o período relevante, solicita a evidência ao responsável e conserva a limitação no relatório. A pressão para fechar o incidente não justifica trocar uma hipótese plausível por uma afirmação factual. Uma cronologia com lacunas visíveis é mais útil para a decisão do que uma sequência aparentemente completa construída por inferência.

5. Avaliar migrações sem ampliar as garantias do relatório

O serviço fictício vai mudar de pasta e a equipa executa analyzeWorkloadMove. O resultado ajuda a analisar compatibilidade com o destino, mas não significa que o movimento já aconteceu. A análise de políticas considera as constraints relevantes para o control package de destino; não demonstra comparação de todas as políticas do projeto. Existe ainda uma limitação importante: flexibilizar restrições para permitir um serviço não suportado não o inclui automaticamente nos checks de background. Ausência de violações pode refletir ausência de cobertura. Prepara o plano em três momentos: análise prévia, execução autorizada e observação do estado resultante. Em cada momento identifica entradas, decisão e evidência de saída. Para uma migração real, o responsável deve determinar que políticas, serviços e recursos exigem verificações adicionais. No exercício, não alteres configurações cloud; escreve quais as informações em falta antes de recomendar uma passagem à fase seguinte. Um exemplo concreto é a integração de um serviço auxiliar de ficheiros que a aplicação de fundos utiliza apenas no fecho mensal. O inventário diário pode não o destacar, mas o seu uso continua relevante. Se o serviço está fora da cobertura do pacote, regista a dependência e pede uma avaliação própria. O silêncio do painel não elimina a necessidade de responder ao requisito. No relatório executivo, separa o que foi analisado, o que mudou e o que permanece sem demonstração. Esta separação ajuda a estimar esforço e a atribuir trabalho sem declarar uma garantia que a ferramenta não forneceu.

6. Rever exceções quando o contexto muda

Uma violação anteriormente aceite como exceção volta a unresolved após outra alteração não conforme. A equipa não deve restaurar a classificação antiga por rotina. O estado pode reabrir quando surgem novas condições. Também não deve interpretar a aplicação a violações existentes de recursos filhos como aprovação ilimitada de violações futuras. É necessário comparar âmbito, pressupostos e justificação. O mesmo responsável continuar no projeto não torna as situações tecnicamente equivalentes. Num ambiente que já tenha admissão à funcionalidade de frameworks, distingue Monitor de Monitor and prevent. O primeiro não demonstra prevenção. A deteção pode demorar após deployment, pelo que um painel vazio minutos depois não é uma prova de avaliação completa. A documentação consultada exige allowlist para esta funcionalidade; o exercício não pressupõe que esteja disponível em qualquer projeto nem define um SLA de deteção a partir de um tempo aproximado. No caso prático, a exceção permitia uma configuração específica durante uma migração. Uma nova release acrescenta um recurso e altera a revisão do controlo. Prepara uma decisão para o comité com as diferenças observadas, impacto e opções: corrigir, obter evidência adicional ou pedir uma decisão de exceção para o novo âmbito. Mantém o estado técnico explícito mesmo que a gestão aceite temporariamente o risco. O registo deve permitir perceber qual a condição avaliada e qual o evento que exige nova revisão. Não uses apenas a data do ticket como prova de validade contínua.

7. Exercício guiado: cobertura de intervalos declarados

Guarda o código como run.py e executa python3 run.py num ambiente local com Python 3.13. O programa usa dados fictícios. Cada requisito identifica recurso, controlo, revisão e intervalo. Cada observação declara o período que cobre; não representa uma amostra pontual automaticamente prolongada. Os intervalos incluem o início e excluem o fim. Assim, dois intervalos adjacentes podem cobrir uma janela sem lacuna, mas dois extremos favoráveis não autorizam preencher o espaço entre eles. Prevê middle-gap antes de ler a saída. As observações cobrem 0–5 e 15–20; uncoveredIntervals deve manter 5–15. Compara adjacent-spans com overlap: ambos podem cobrir a janela, mas a sobreposição não duplica tempo. Depois substitui a observação por approval ou exception. O programa conserva o registo e mantém a lacuna técnica. Acrescenta uma falha dentro de um período favorável: coverageComplete pode ser verdadeiro, mas supportedUnderDeclaredEvidence permanece falso. Uma cobertura temporal completa não resolve evidência contraditória. Muda a revisão ou o recurso de uma observação e explica por que não satisfaz o requisito original. Por fim, marca o inventário como incompleto. O resultado deve conservar essa incerteza mesmo quando os requisitos listados têm observações suficientes. Entrega a tua interpretação com o que falta recolher, quem o pode fornecer e que decisão depende disso. O exercício compara declarações; não autentica registos, verifica controlos reais nem decide conformidade legal. Para analisar duas revisões sucessivas, divide explicitamente o trabalho em janelas coerentes.

8. Preparar uma aceitação que outra equipa consegue manter

Reúne agora os resultados do serviço de reconciliação. O modo de aprovação foi confirmado, a dependência da chave tem responsável e a análise de movimento foi documentada. Ainda existe uma hora sem evidência adequada do controlo C7. A recomendação de aceitação deve preservar essa lacuna. A gestão pode precisar de uma decisão sobre prazo e risco, mas a conclusão técnica não deve mudar apenas porque a data de entrega chegou. Treina uma comunicação curta em inglês: identifica a janela exigida, os períodos demonstrados e a ação seguinte. Uma resposta adequada diz que o intervalo intermédio permanece sem observação e atribui a recolha a um responsável. Uma resposta inadequada diz que a aprovação de mudança torna todas as verificações satisfeitas. Acrescenta o momento de nova revisão e o critério que permitiria alterar a conclusão. Esta prática serve tanto para um comité de projeto como para uma passagem de turno internacional. O bloco liga-se ao objetivo 5.1 do guia PCSE consultado, com foco em âmbito e correspondência entre requisito, serviço e controlo. Não cobre sozinho todo o domínio. O exercício local não aprova produção nem verifica se o requisito escolhido é juridicamente suficiente. A evidência de aprendizagem demonstra raciocínio sobre os casos apresentados. A aceitação real exige fontes do ambiente, âmbito acordado e decisão dos responsáveis competentes. No resumo final, indica o que está demonstrado, o que permanece desconhecido e a ação concreta que reduz essa incerteza.

"""Offline coverage worksheet for declared synthetic intervals, not a compliance verifier."""
import copy
import hashlib
import itertools
import json
from pathlib import Path


def require(ok,message):
    if not ok: raise ValueError(message)


def text(value):
    return isinstance(value,str) and bool(value.strip())


def minute(value):
    return type(value) is int and value>=0


def scope(row):
    require(isinstance(row,dict),'record object')
    require(all(text(row.get(k))for k in ('resource','control','revision')),'scope fields')
    return tuple(row[k]for k in ('resource','control','revision'))


def interval(row,as_of):
    require(minute(row.get('start'))and minute(row.get('end')),'interval numbers')
    require(row['start']<row['end']<=as_of,'ordered nonfuture interval')
    return row['start'],row['end']


def gaps(start,end,spans):
    cursor=start;missing=[]
    for left,right in sorted(spans):
        left=max(start,left);right=min(end,right)
        if right<=left:continue
        if left>cursor:missing.append([cursor,left])
        cursor=max(cursor,right)
    if cursor<end:missing.append([cursor,end])
    return missing


def inspect(data):
    require(isinstance(data,dict)and minute(data.get('asOf')),'input and asOf')
    require(type(data.get('inventoryComplete'))is bool,'inventory flag')
    require(isinstance(data.get('requirements'),list)and data['requirements'],'requirements')
    require(isinstance(data.get('evidence'),list),'evidence')
    identifiers=set();pairs=set()
    for req in data['requirements']:
        k=scope(req);interval(req,data['asOf'])
        require(k[:2]not in pairs,'one revision per resource and control');pairs.add(k[:2])
    for row in data['evidence']:
        scope(row);interval(row,data['asOf'])
        require(text(row.get('id'))and row['id']not in identifiers,'unique evidence id');identifiers.add(row['id'])
        require(row.get('kind')in('observation','approval','exception'),'evidence kind')
        require(row.get('outcome')in('pass','fail','unknown'),'evidence outcome')
    rows=[];used=set()
    for req in sorted(data['requirements'],key=scope):
        key=scope(req);matching=[];ignored=[]
        for evidence in data['evidence']:
            if scope(evidence)!=key:
                if scope(evidence)[:2]==key[:2]:ignored.append({'id':evidence['id'],'reason':'different-revision'})
                continue
            if evidence['end']<=req['start']or evidence['start']>=req['end']:
                ignored.append({'id':evidence['id'],'reason':'outside-window'});continue
            matching.append(evidence);used.add(evidence['id'])
        positive=[r for r in matching if r['kind']=='observation'and r['outcome']=='pass']
        failed=sorted(r['id']for r in matching if r['kind']=='observation'and r['outcome']=='fail')
        unknown=sorted(r['id']for r in matching if r['kind']=='observation'and r['outcome']=='unknown')
        missing=gaps(req['start'],req['end'],[(r['start'],r['end'])for r in positive])
        rows.append(dict(resource=key[0],control=key[1],revision=key[2],window=[req['start'],req['end']],
                         uncoveredIntervals=missing,positiveEvidenceIds=sorted(r['id']for r in positive),
                         failedEvidenceIds=failed,unknownEvidenceIds=unknown,
                         approvalIds=sorted(r['id']for r in matching if r['kind']=='approval'),
                         exceptionIds=sorted(r['id']for r in matching if r['kind']=='exception'),
                         ignored=sorted(ignored,key=lambda x:(x['id'],x['reason'])),
                         coverageComplete=not missing,contradictoryOrUnknown=bool(failed or unknown)))
    return dict(requirements=rows,inventoryCoverageUnproven=not data['inventoryComplete'],
                unassessedEvidenceIds=sorted(identifiers-used),
                supportedUnderDeclaredEvidence=data['inventoryComplete']and all(r['coverageComplete']and not r['contradictoryOrUnknown']for r in rows),
                evidenceAuthenticityVerified=False,actualControlEvaluated=False,productionAcceptanceAuthorized=False)


def sample():
    return dict(asOf=30,inventoryComplete=True,
                requirements=[dict(resource='training/r1',control='C7',revision='v3',start=0,end=20)],
                evidence=[dict(id='e1',resource='training/r1',control='C7',revision='v3',start=0,end=20,kind='observation',outcome='pass')])


def checks():
    fixtures=[]
    def check(name,data,**expected):
        before=copy.deepcopy(data);actual=inspect(data);assert data==before
        row=actual['requirements'][0]
        for k,v in expected.items():assert row[k]==v,(name,k,row[k],v)
        fixtures.append(dict(id=name,**actual));return actual
    check('full-window',sample(),uncoveredIntervals=[],coverageComplete=True)
    x=sample();x['evidence'][0]['end']=10;x['evidence'].append(dict(x['evidence'][0],id='e2',start=10,end=20));check('adjacent-spans',x,uncoveredIntervals=[])
    x=sample();x['evidence'][0]['end']=5;x['evidence'].append(dict(x['evidence'][0],id='e2',start=15,end=20));check('middle-gap',x,uncoveredIntervals=[[5,15]])
    x=sample();x['evidence'][0]['end']=15;x['evidence'].append(dict(x['evidence'][0],id='e2',start=10,end=20));check('overlap',x,uncoveredIntervals=[])
    x=sample();x['evidence'][0].update(start=20,end=25);check('outside-half-open-window',x,uncoveredIntervals=[[0,20]],ignored=[dict(id='e1',reason='outside-window')])
    x=sample();x['evidence'][0]['revision']='v2';check('different-revision',x,uncoveredIntervals=[[0,20]],ignored=[dict(id='e1',reason='different-revision')])
    x=sample();x['evidence'][0]['resource']='training/r2';a=check('different-resource',x,uncoveredIntervals=[[0,20]]);assert a['unassessedEvidenceIds']==['e1']
    x=sample();x['evidence'].append(dict(x['evidence'][0],id='e2',start=5,end=6,outcome='fail'));a=check('failure-inside-pass',x,coverageComplete=True,failedEvidenceIds=['e2']);assert not a['supportedUnderDeclaredEvidence']
    x=sample();x['evidence'].append(dict(x['evidence'][0],id='e2',outcome='unknown'));a=check('unknown-inside-pass',x,unknownEvidenceIds=['e2']);assert not a['supportedUnderDeclaredEvidence']
    x=sample();x['evidence'][0]['kind']='approval';check('approval-only',x,uncoveredIntervals=[[0,20]],approvalIds=['e1'])
    x=sample();x['evidence'][0]['kind']='exception';check('exception-only',x,uncoveredIntervals=[[0,20]],exceptionIds=['e1'])
    x=sample();x['inventoryComplete']=False;a=check('incomplete-inventory',x,coverageComplete=True);assert a['inventoryCoverageUnproven']and not a['supportedUnderDeclaredEvidence']
    x=sample();x['evidence']=[];check('no-evidence',x,uncoveredIntervals=[[0,20]])
    combinations=0
    for start,end,kind,outcome in itertools.product((0,5,10),(15,20),('observation','approval','exception'),('pass','fail','unknown')):
        x=sample();x['evidence'][0].update(start=start,end=end,kind=kind,outcome=outcome)
        actual=inspect(x);assert actual['supportedUnderDeclaredEvidence']==(start==0 and end==20 and kind=='observation'and outcome=='pass');combinations+=1
    x=sample();x['evidence']=[dict(x['evidence'][0],id='e'+str(i),start=i*5,end=(i+1)*5)for i in range(3)];reference=inspect(x);permutations=0
    for order in itertools.permutations(x['evidence']):
        y=copy.deepcopy(x);y['evidence']=list(order);assert inspect(y)==reference;permutations+=1
    invalid=[]
    for k,v in [('asOf',True),('asOf',-1),('inventoryComplete',1),('requirements',[]),('evidence',None)]:
        x=sample();x[k]=v;invalid.append(x)
    for k,v in [('resource',''),('control',''),('revision',''),('start',True),('start',20),('end',31)]:
        x=sample();x['requirements'][0][k]=v;invalid.append(x)
    for k,v in [('id',''),('kind','snapshot'),('outcome','green'),('start',1.5),('end',0),('resource',None),('revision','')]:
        x=sample();x['evidence'][0][k]=v;invalid.append(x)
    x=sample();x['evidence'].append(dict(x['evidence'][0]));invalid.append(x)
    x=sample();x['requirements'].append(dict(x['requirements'][0],revision='v2'));invalid.append(x)
    for x in invalid:
        try:inspect(x)
        except ValueError:pass
        else:raise AssertionError('invalid accepted')
    return dict(fixtures=fixtures,stateCombinations=combinations,inputPermutations=permutations,invalidInputs=len(invalid),
                inputPreserved=True,orderIndependent=True,network=False,cloudExecuted=False,persistentWrites=False,
                scriptSha256=hashlib.sha256(Path(__file__).read_bytes()).hexdigest())


if __name__=='__main__':print(json.dumps(checks(),ensure_ascii=False,indent=2))
NA PRÁTICA

Duas observações favoráveis deixam uma hora sem evidência; uma aprovação de mudança não demonstra o estado técnico desse intervalo.

Armadilhas comuns

Contar política como decisão manual; confundir assinatura com ação observada; ampliar cobertura de monitorização; interpolar sucesso numa lacuna.

Tópicos relacionados: Responsabilidade por controlos · Ciclo de vida das aprovações · Handover e evidência operacional

Leva esta ideia contigo

Uma conclusão de controlo só abrange o âmbito e o período sustentados. Aprovações, exceções e observações devem conservar o seu significado.

Criar conta

Referência: Approving Access Approval requests · Current linked guide; edition date unconfirmed (2026-09-30 inspection)

Google Cloud é uma marca comercial de Google LLC. A dr.pt é uma plataforma de preparação independente e não está afiliada, associada, patrocinada, autorizada nem aprovada por Google. Os conteúdos e as perguntas são originais, não são perguntas oficiais de exame, e concluir os nossos testes não atribui nem garante qualquer certificação. Os nomes são usados apenas para identificar o tema. Todas as outras marcas pertencem aos respetivos titulares.