← Professional Cloud Security Engineer: controlos e evidência
13 / 13 · 120 MIN

Governação, âmbito e evidência de controlos

Traduz requisitos em controlos com âmbito, responsáveis e evidência adequada à aceitação operacional.

Transformar um requisito num âmbito verificável

Começa por uma afirmação que a equipa possa demonstrar. “A plataforma é conforme” não identifica recursos, dados, operações, período ou critérios. No projeto fictício desta aula, o requisito interno abrange o ambiente primário e o de recuperação. O dossier de aceitação precisa de mostrar ambos. Uma média de resultados positivos pode esconder que a recuperação não foi revista. Os exemplos não descrevem procedimentos internos BNP Paribas nem estabelecem uma obrigação legal específica. Constrói uma matriz com uma linha por recurso e controlo aplicável. Regista o requisito, o responsável, a forma de implementação, a evidência e as limitações. Se um controlo não se aplica, documenta a razão e quem aprovou essa classificação. Não uses um campo vazio para significar simultaneamente desconhecido, dispensado e verificado. Estes estados levam a ações diferentes e precisam de permanecer distinguíveis no relatório para o comité. Inclui mudanças de âmbito. Um novo destino de backup, um serviço adicional ou uma rota de suporte pode exigir atualizar a matriz. A evidência anterior continua útil no seu âmbito, mas não cobre automaticamente o componente novo. Antes da decisão, pede ao dono do serviço que confirme o inventário e aos responsáveis pelos controlos que expliquem as lacunas. O PM coordena essa revisão e conserva decisões rastreáveis; não substitui a interpretação especializada dos requisitos apenas por escolher um produto com um nome adequado.

Verificar localização por recurso e serviço

Uma restrição de localização deve ser lida com o seu âmbito técnico. resource locations limita a criação de recursos suportados em localizações permitidas. Não move automaticamente recursos antigos para a região escolhida. Se o inventário inclui um recurso criado antes da política, a equipa precisa de analisar esse recurso separadamente. Um teste que demonstra a recusa de uma nova criação fora da região é útil, mas responde apenas a essa operação testada. Também não transformes a localização de criação numa promessa universal sobre armazenamento e processamento de dados. Existem recursos globais, tipos sem seleção de localização e comportamentos próprios de cada serviço. Prepara uma linha por componente com a configuração relevante e a documentação aplicável. Para o serviço fictício de reconciliação, inclui primário, recuperação, cópias exportadas e observabilidade quando fazem parte do âmbito aprovado. Evita inferir a localização dos dados a partir da região de uma única VM. O plano de mudança deve preservar continuidade. Uma nova restrição pode impedir operações de criação de que uma rotina depende, mesmo sem afetar imediatamente recursos existentes. Identifica essas rotinas e ensaia a mudança em âmbito controlado. Se for necessária migração de dados, trata-a como trabalho próprio, com dono, validação e contingência. Na apresentação ao comité, separa o controlo que já impede novas criações do trabalho ainda necessário para o inventário anterior e das verificações específicas de cada serviço.

Relacionar pacote, serviço e versão instalada

Assured Workloads organiza controlos em pacotes com âmbitos próprios. Antes de acrescentar um serviço a uma pasta, confirma suporte no pacote escolhido. Encontrar esse serviço noutro pacote não demonstra que está abrangido pelo atual. A decisão de arquitetura deve indicar a necessidade funcional, o controlo requerido e a correspondência documentada. Se a correspondência não existir, a equipa precisa de rever o desenho ou a decisão de âmbito, em vez de apenas alterar o texto do relatório. Uma configuração também tem uma versão efetiva. A existência de uma atualização disponível não significa que já tenha sido avaliada e aplicada à pasta. Mantém separados o estado atual, a proposta e a decisão de adoção. No exemplo fictício, a equipa de projeto quer citar a versão nova antes de concluir a análise de impacto. O PM deve pedir confirmação do estado instalado e atribuir a revisão da mudança, incluindo dependências que possam ser afetadas pelos valores propostos. Prepara uma nota curta de decisão: configuração atual, alteração proposta, motivo, impacto, ensaio e responsável. Se a atualização for adiada, explica a decisão e o acompanhamento necessário sem declarar que a nova configuração já está ativa. Depois da aplicação, recolhe evidência do resultado no âmbito correto. A documentação mais recente ajuda a planear, mas a aceitação depende também do que está efetivamente configurado no workload que será entregue à operação.

Tratar exceções sem as contar como correções

Uma exceção aprovada e um controlo corrigido são resultados diferentes. Em Assured Workloads, Exception regista uma decisão com justificação; Resolved representa resolução da violação. A equipa deve manter o estado técnico e a decisão de risco visíveis. No cenário fictício, um controlo do ambiente primário tem uma exceção temporária. Essa decisão não preenche a evidência em falta do ambiente de recuperação nem prova que a configuração subjacente mudou. Define o âmbito da exceção, o responsável, as condições, o acompanhamento e o momento de revisão segundo o processo interno. Uma aprovação ambígua pode ser interpretada como permissão permanente por uma equipa que só recebe o ticket meses depois. Regista o que foi aceite e o que continua por fazer. Se a arquitetura mudar, reavalia a aplicabilidade da decisão em vez de a transportar automaticamente para recursos novos ou para uma finalidade diferente. A resposta operacional também precisa de cobertura. Os emails de Assured Workloads Monitoring não abrangem resource violations. Um processo que espera apenas essas mensagens deixa uma categoria sem observação adequada. Confirma os mecanismos disponíveis e atribui a sua utilização. No comité, comunica lacunas e exceções separadamente, com ações e donos. Evita transformar ausência de notificações, ausência de perguntas ou uma aprovação administrativa numa conclusão técnica de que todos os requisitos foram satisfeitos durante todo o período.

Rever o âmbito de acesso do fornecedor

Um pedido de apoio precisa de uma descrição suficientemente precisa para ser aprovado com conhecimento do âmbito. Em Access Approval, confirma recurso, finalidade, características de localização e duração. Aprovar um recurso pai também abrange os seus descendentes. Se a necessidade do cenário se limita a um objeto, não registes uma aprovação de bucket como se estivesse limitada apenas a esse objeto. A descrição do ticket não altera o âmbito técnico do pedido. A aprovação também não deve ser apresentada como exclusiva do funcionário que a iniciou. As características aprovadas podem abranger outros funcionários correspondentes, dentro das condições e do período. Isso não significa acesso irrestrito nem criação de novos papéis IAM. O PM deve comunicar o que foi efetivamente aprovado e quem, na organização, acompanha a intervenção. Uma decisão precisa evita tanto promessas demasiado fortes como interpretações de acesso sem limites. Ao consultar pedidos pendentes na consola, confirma o nível de recurso selecionado. A vista de uma pasta não demonstra automaticamente que todos os projetos descendentes estão sem pedidos. Define a rotina de acompanhamento com o âmbito correto e os responsáveis autorizados. Para o exercício, prepara uma nota fictícia com necessidade, âmbito pedido, diferença encontrada e ação seguinte. Não uses dados reais de suporte. Relaciona depois a evidência de acesso com a decisão, preservando as limitações e exceções documentadas para os serviços envolvidos.

Interpretar registos sem lhes atribuir outro significado

Um campo de auditoria deve ser lido segundo a sua definição. Em Access Transparency, o país do escritório permanente e o país físico indicado para o acesso são campos diferentes. Se principalOfficeCountry é PT e principalPhysicalLocationCountry é DE, não uses PT como local físico apenas porque aparece primeiro. Nenhum desses campos, isoladamente, demonstra a região onde os dados foram armazenados. A pergunta do auditor determina que evidência é necessária. No exercício fictício, o comité pede três afirmações: qual o âmbito aprovado, que acesso foi registado e qual a configuração de localização dos recursos. Prepara três respostas com referências apropriadas. O pedido de aprovação não substitui o registo de acesso; o registo de acesso não substitui a configuração do recurso. Uma ligação entre documentos ajuda a investigação, mas não torna os seus significados intercambiáveis. Preserva também valores desconhecidos em vez de os preencher com uma suposição conveniente. Na nota de evidência, inclui período, origem, recurso e limites da observação. Evita copiar payloads sensíveis quando bastam identificadores delimitados e referências autorizadas. Se dois registos parecem contradizer-se, verifica se descrevem a mesma operação e o mesmo momento antes de concluir que um deles está errado. O objetivo do PM é coordenar uma explicação rastreável que as equipas técnicas e de controlo consigam rever, sem converter cada campo disponível numa garantia mais ampla do que ele sustenta.

Atribuir responsabilidades que funcionem durante o incidente

Responsabilidade partilhada precisa de tarefas concretas. Para cada controlo, identifica quem configura, quem opera, quem observa falhas e quem decide alterações. A distribuição varia com o serviço e o workload; uma matriz genérica pode orientar perguntas, mas não substitui o acordo operacional. No caso fictício, o compromisso interno exige uma atualização ao negócio em 15 minutos. O prazo de resposta do fornecedor é diferente. A espera pelo suporte não elimina a necessidade de comunicar factos, impacto e próxima atualização. Prepara o handover com ações que a equipa de produção consegue executar. Inclui contactos, âmbito de acesso, localização da evidência, critérios de escalamento e autoridade para decisões urgentes. Um nome numa tabela não demonstra capacidade operacional. Faz uma passagem guiada com um incidente sintético: quem recebe o alerta, quem confirma o impacto, quem abre o pedido e quem mantém o negócio informado? Regista as dependências que impedem a autonomia pretendida. Na aceitação, evita um único estado “concluído” para atividades diferentes. A infraestrutura pode estar entregue enquanto falta formação, acesso ou observação de um controlo. Relaciona cada pendência com consequência, responsável e data acordada. Se existir aceitação faseada, delimita o que entrou efetivamente em operação. Essa clareza ajuda a gerir prazo e orçamento sem ocultar trabalho restante, e permite que a equipa RUN mantenha o serviço depois de o projeto deixar de ter pessoas dedicadas à implementação.

Exercício: cobertura de recursos e períodos

O exercício Python usa uma matriz fictícia de requisitos e evidências com intervalos. Cada requisito identifica recurso, controlo e responsável. Cada evidência declara um resultado e um período no formato início incluído, fim excluído. Dois intervalos adjacentes podem cobrir todo o período; dois intervalos separados deixam uma lacuna. O programa compara essas declarações, não prova que um controlo funcionou continuamente nem determina conformidade legal. Antes de executar python3 run.py, prevê o resultado com evidência apenas do primário. Recuperação deve continuar por demonstrar. Depois divide a evidência de recuperação em dois intervalos que se tocam e observa a cobertura declarada. Introduz uma falha num intervalo dentro do período: ela permanece visível mesmo que exista uma declaração positiva abrangente. Uma exceção aprovada é apresentada separadamente e nunca convertida em pass. Um requisito sem responsável continua a impedir a conclusão local de cobertura completa. O programa ignora para a cobertura evidências de recursos ou períodos exteriores ao âmbito, mas lista os respetivos identificadores para revisão. Usa esses resultados para escrever a nota ao comité: âmbito avaliado, lacunas, falhas, exceções e próxima ação. Não uses allRequirementsCovered como aprovação de produção. O resumo da aula é manter a correspondência entre requisito, recurso, período, responsável e evidência. Quando essa correspondência falta, descreve a lacuna e atribui trabalho para a resolver, preservando a diferença entre uma decisão aceite e um controlo demonstrado.

"""Original offline control-evidence coverage worksheet.

Intervals are [start,end). Evidence coverage is a supplied assertion, not proof
that a technical control operated continuously. Exceptions never become passes.
No legal determination, cloud inspection, evidence authentication or production action.
"""
from copy import deepcopy
from hashlib import sha256
from itertools import permutations, product
from math import isfinite
from pathlib import Path
import json


def text(v):
    if not isinstance(v, str) or not v.strip():
        raise ValueError('expected nonempty string')
    return v


def interval(start, end):
    for n in (start, end):
        if type(n) not in (int, float) or not isfinite(n):
            raise ValueError('invalid interval value')
    if start >= end:
        raise ValueError('empty or reversed interval')
    return start, end


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


def coverage(requirements, evidence, start=0, end=6):
    interval(start, end)
    if not isinstance(requirements, list) or not requirements or not isinstance(evidence, list):
        raise ValueError('requirements and evidence lists required')
    required = {}
    for item in requirements:
        if not isinstance(item, dict):
            raise ValueError('invalid requirement')
        key = text(item.get('resource')), text(item.get('control'))
        if key in required:
            raise ValueError('duplicate requirement')
        owner = item.get('owner')
        if owner is not None:
            text(owner)
        required[key] = owner
    seen, records, outside_scope = set(), {}, []
    for item in evidence:
        if not isinstance(item, dict):
            raise ValueError('invalid evidence')
        identifier = text(item.get('id'))
        if identifier in seen:
            raise ValueError('duplicate evidence ID')
        seen.add(identifier)
        key = text(item.get('resource')), text(item.get('control'))
        left, right = interval(item.get('start'), item.get('end'))
        state = item.get('result')
        if state not in ('pass', 'fail', 'unknown'):
            raise ValueError('invalid result')
        exception = item.get('exception')
        if exception is not None:
            if not isinstance(exception, dict):
                raise ValueError('invalid exception')
            text(exception.get('id'))
            interval(exception.get('start'), exception.get('end'))
            if type(exception.get('approved')) is not bool:
                raise ValueError('invalid exception approval')
        if key not in required or right <= start or left >= end:
            outside_scope.append(identifier)
        else:
            records.setdefault(key, []).append(item)
    rows = []
    for key, owner in sorted(required.items()):
        positive, failures, exceptions = [], [], []
        for item in records.get(key, []):
            span = [max(start, item['start']), min(end, item['end'])]
            if item['result'] == 'pass':
                positive.append(span)
            elif item['result'] == 'fail':
                failures.append(dict(id=item['id'], interval=span))
            ex = item.get('exception')
            if ex and ex['approved'] and ex['start'] <= start and ex['end'] >= end:
                exceptions.append(ex['id'])
        missing = gaps(positive, start, end)
        status = 'failed' if failures else ('unproven' if missing else 'covered-by-supplied-evidence')
        rows.append(dict(resource=key[0], control=key[1], owner=owner,
                         ownershipMissing=owner is None, status=status,
                         uncoveredIntervals=missing,
                         failures=sorted(failures, key=lambda x: x['id']),
                         approvedExceptions=sorted(set(exceptions))))
    return dict(rows=rows, outsideScopeEvidence=sorted(outside_scope),
                allRequirementsCovered=all(r['status'] == 'covered-by-supplied-evidence' and not r['ownershipMissing'] for r in rows),
                actualComplianceProven=False, productionAuthorized=False)


def main():
    requirements = [dict(resource='primary', control='access', owner='APS'),
                    dict(resource='recovery', control='access', owner='APS')]
    primary = dict(id='p', resource='primary', control='access', start=0, end=6, result='pass')
    recovery = dict(primary, id='r', resource='recovery')
    fixtures = []

    def case(name, evidence, expected, req=None):
        req = requirements if req is None else req
        before = deepcopy((req, evidence))
        result = coverage(req, evidence)
        assert result['allRequirementsCovered'] is expected, name
        assert (req, evidence) == before
        fixtures.append(dict(id=name, **result))
        return result

    case('both-environments', [primary, recovery], True)
    case('missing-recovery', [primary], False)
    case('adjacent-evidence', [primary, dict(recovery, end=3), dict(recovery, id='r2', start=3)], True)
    case('period-gap', [primary, dict(recovery, end=2), dict(recovery, id='r2', start=3)], False)
    case('overlap', [primary, dict(recovery, end=4), dict(recovery, id='r2', start=3)], True)
    case('conflicting-failure', [primary, recovery, dict(recovery, id='r2', result='fail', start=2, end=3)], False)
    exception = dict(id='waiver1', start=0, end=6, approved=True)
    case('approved-exception-not-pass', [primary, dict(recovery, result='fail', exception=exception)], False)
    case('expired-exception', [primary, dict(recovery, result='fail', exception=dict(exception, end=5))], False)
    case('unknown-evidence', [primary, dict(recovery, result='unknown')], False)
    case('outside-period', [primary, recovery, dict(recovery, id='r2', result='fail', start=6, end=8)], True)
    case('outside-resource', [primary, recovery, dict(recovery, id='r2', resource='development', result='fail')], True)
    case('missing-owner', [primary, recovery], False, [requirements[0], dict(requirements[1], owner=None)])
    combinations = 0
    for left_end, right_start in product(range(1, 7), range(0, 6)):
        spans = [dict(recovery, end=left_end), dict(recovery, id='r2', start=right_start)]
        result = coverage(requirements, [primary, *spans])
        covered_ticks = {t for t in range(6) if any(x['start'] <= t < x['end'] for x in spans)}
        assert result['allRequirementsCovered'] == (covered_ticks == set(range(6)))
        combinations += 1
    records = [primary, dict(recovery, end=3), dict(recovery, id='r2', start=3)]
    expected = coverage(requirements, records)
    permutations_checked = 0
    for order in permutations(records):
        assert coverage(requirements, list(order)) == expected
        permutations_checked += 1
    invalid = [
        ([], [], {}),
        ([requirements[0], requirements[0]], [], {}),
        ([dict(requirements[0], owner='')], [], {}),
        (requirements, [primary, primary], {}),
        (requirements, [dict(primary, result=True)], {}),
        (requirements, [dict(primary, start=3, end=3)], {}),
        (requirements, [dict(primary, start=True)], {}),
        (requirements, [dict(primary, end=float('inf'))], {}),
        (requirements, [dict(primary, exception=dict(exception, approved='true'))], {}),
        (requirements, [dict(primary, exception=dict(exception, id=''))], {}),
        (requirements, [dict(primary, resource='')], {}),
        (requirements, [None], {}),
        (requirements, [], dict(start=6, end=0)),
        (requirements, [], dict(end=float('nan'))),
    ]
    for req, ev, kwargs in invalid:
        try:
            coverage(req, ev, **kwargs)
        except ValueError:
            pass
        else:
            raise AssertionError('invalid input accepted')
    print(json.dumps(dict(labId='pcse-control-scope', fixtures=fixtures,
                          intervalCombinations=combinations, inputPermutations=permutations_checked,
                          invalidInputs=len(invalid), inputPreserved=True, orderIndependent=True,
                          network=False, cloudExecuted=False, persistentWrites=False,
                          scriptSha256=sha256(Path(__file__).read_bytes()).hexdigest()), indent=2))


if __name__ == '__main__':
    main()
NA PRÁTICA

O primário tem evidência, a recuperação ainda não foi revista e uma exceção foi aprovada; o comité precisa de ver os três estados.

Armadilhas comuns

Tratar restrição de criação como migração, atualização disponível como instalada, exceção como correção e silêncio de notificações como prova de cobertura.

Tópicos relacionados: Gestão de risco e exceções · Passagem a produção e responsabilidades · Auditoria de acesso e localização de dados

Leva esta ideia contigo

Declara apenas o âmbito e período sustentados pela evidência e mantém exceções e responsabilidades visíveis.

Criar conta

Referência: Shared responsibilities and shared fate on Google Cloud · 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.