← CCNP Enterprise: núcleo ENCOR e operação
20 / 20 · 55 MIN

AAA, CoPP e acesso de recuperação

Distingue rejeição de indisponibilidade e interpreta a ACL de classificação no contexto da política.

Três perguntas diferentes no acesso administrativo

Autenticação verifica a identidade apresentada; autorização decide o que essa identidade pode fazer; accounting regista a atividade prevista pela configuração. Um login que funciona não demonstra que todos os comandos necessários estão autorizados nem que os registos chegaram ao coletor. Num ensaio de entrega ao RUN, usa um perfil de consulta e um perfil de mudança para observar uma operação permitida e uma negada segundo o contrato. Não resolvas uma autorização insuficiente atribuindo privilégios globais sem rever o papel esperado. Mantém o identificador do utilizador, a operação, o instante e o resultado na evidência, sem expor palavras-passe ou segredos de integração.

Rejeição não é indisponibilidade

Considera a lista conceptual remote, local. Se o método remoto devolver PASS, o modelo termina com sucesso; se devolver FAIL, termina com rejeição. Só ERROR permite tentar o método seguinte neste modelo da semântica documentada de autenticação AAA. Um operador com credenciais rejeitadas não passa automaticamente a usar a conta local. Para testar recuperação, distingue deliberadamente a indisponibilidade do serviço de uma rejeição válida e preserva uma sessão de recuperação. O script fornece estes resultados como dados de entrada: não implementa TACACS+, RADIUS, descoberta de servidores mortos nem tempos de espera. Num equipamento, o grupo remoto pode tentar os seus servidores antes de devolver o resultado à lista de métodos.

O significado da ACL depende do uso

Na ACL de filtragem da aula anterior, permit e deny eram decisões sobre o pacote naquele ponto. Numa ACL usada para selecionar tráfego de uma classe CoPP, permit significa que o pacote corresponde à classe; a ação da policy-map decide depois o tratamento. O modelo exclui SSH de 192.0.2.10 com deny e seleciona o restante SSH com permit para uma classe hipotética cuja ação é drop. Assim, a palavra permit pode conduzir a descarte nesta utilização. O resultado not-selected não é uma autorização global: outra classe, a política por omissão ou outro controlo pode atuar. O exercício regista apenas seleção para esta classe, sem simular a política completa do equipamento.

Proteger a CPU sem perder a operação

CoPP trata tráfego que alcança o plano de controlo; não substitui a política de segurança de todas as aplicações que transitam no equipamento. Antes de mudar classes ou taxas, identifica os protocolos necessários, os peers e o comportamento normal e de recuperação. Uma CPU mais baixa não prova que o serviço melhorou se a nova política também impedir adjacências ou administração legítima. Correlaciona contadores de classe e descarte com eventos de routing, disponibilidade de gestão e tempos da mudança. Os limiares dependem da plataforma e da carga; o modelo não fornece uma taxa pronta para produção nem mede capacidade de CPU. A aceitação exige observação no equipamento e versão de destino.

Executar o modelo e preparar a mudança real

Guarda o script abaixo como run.py e executa python3 run.py /tmp/access-evidence.json. Usa apenas a biblioteca standard de Python, sem Docker, rede ou credenciais. Duas execuções passaram 23 verificações distribuídas por três modelos: ACL ordenada, seleção de uma classe CoPP e sequência de resultados AAA. O JSON guarda entradas e resultados esperados e obtidos, permitindo alterar uma condição e compreender a decisão. Nenhum resultado demonstra execução IOS XE ou aceitação de produção. Para uma mudança real, confirma acesso de recuperação, configuração completa, métodos aplicados às linhas corretas, perfis autorizados, observabilidade e rollback. Fecha a janela apenas depois de testar o caminho normal e o caminho de recuperação acordado, documentando o que ainda não foi exercitado.

"""Original teaching models only: IPv4 ACL decisions, CoPP selection and AAA outcomes.
Run: python3 run.py /tmp/access-evidence.json
No packets sent, no devices contacted, no credentials used, no hardware emulation.
"""
import datetime,hashlib,ipaddress,json,pathlib,platform,sys
checks=[]
def check(name,actual,expected,inputs):
 assert actual==expected,(name,actual,expected)
 checks.append(dict(name=name,inputs=inputs,actual=actual,expected=expected))
def address_match(value,base,wildcard):
 mask=(~int(ipaddress.IPv4Address(wildcard)))&0xffffffff
 return (int(ipaddress.IPv4Address(value))&mask)==(int(ipaddress.IPv4Address(base))&mask)
def packet(src='192.0.2.10',dst='198.51.100.20',proto='tcp',sport=51000,dport=443,flags=()):
 return dict(src=src,dst=dst,proto=proto,sport=sport,dport=dport,flags=list(flags))
def rule(seq,action,proto='ip',src='0.0.0.0',sw='255.255.255.255',dst='0.0.0.0',dw='255.255.255.255',sport=None,dport=None,established=False):
 assert action in ['permit','deny']
 return dict(seq=seq,action=action,proto=proto,src=src,sw=sw,dst=dst,dw=dw,sport=sport,dport=dport,established=established)
def evaluate(rules,p):
 for r in sorted(rules,key=lambda r:r['seq']):
  if r['proto']!='ip' and r['proto']!=p['proto']:continue
  if not address_match(p['src'],r['src'],r['sw']) or not address_match(p['dst'],r['dst'],r['dw']):continue
  if r['sport'] is not None and p['sport']!=r['sport']:continue
  if r['dport'] is not None and p['dport']!=r['dport']:continue
  if r['established'] and (p['proto']!='tcp' or not(set(p['flags'])&{'ACK','RST'})):continue
  return dict(action=r['action'],sequence=r['seq'])
 return dict(action='deny',sequence=None)
def aaa(outcomes):
 visited=[]
 for name,result in outcomes:
  assert result in ['PASS','FAIL','ERROR']
  visited.append(name)
  if result!='ERROR':return dict(result=result,visited=visited)
 return dict(result='ERROR',visited=visited)
def acl_check(name,rules,p,expected):check(name,evaluate(rules,p),expected,dict(rules=rules,packet=p))
permit=rule(10,'permit','tcp','192.0.2.0','0.0.0.255','198.51.100.20','0.0.0.0',dport=443)
acl=[permit];flow=packet()
acl_check('approved HTTPS request matches sequence 10',acl,flow,dict(action='permit',sequence=10))
acl_check('unapproved source reaches implicit deny',acl,packet(src='203.0.113.8'),dict(action='deny',sequence=None))
acl_check('unapproved service reaches implicit deny',acl,packet(dport=22),dict(action='deny',sequence=None))
acl_check('UDP 443 is not TCP 443',acl,packet(proto='udp'),dict(action='deny',sequence=None))
acl_check('destination outside exact host is not matched',acl,packet(dst='198.51.100.21'),dict(action='deny',sequence=None))
early_deny=rule(5,'deny','ip');acl_check('earlier deny shadows intended permit',[permit,early_deny],flow,dict(action='deny',sequence=5))
late_deny=rule(20,'deny','ip');acl_check('later deny does not override first permit',[permit,late_deny],flow,dict(action='permit',sequence=10))
reverse=packet(src='198.51.100.20',dst='192.0.2.10',sport=443,dport=51000,flags=['ACK'])
acl_check('outbound permission creates no automatic reverse permission',acl,reverse,dict(action='deny',sequence=None))
return_rule=rule(10,'permit','tcp','198.51.100.20','0.0.0.0','192.0.2.0','0.0.0.255',sport=443,established=True)
acl_check('separate return rule matches ACK and source port',[return_rule],reverse,dict(action='permit',sequence=10))
acl_check('established keyword excludes SYN-only packet',[return_rule],{**reverse,'flags':['SYN']},dict(action='deny',sequence=None))
acl_check('ACK matching does not consult session history',[return_rule],packet(src='198.51.100.20',dst='192.0.2.88',sport=443,dport=59999,flags=['ACK']),dict(action='permit',sequence=10))
for value,expected in [('192.0.2.0',True),('192.0.2.254',True),('192.0.2.3',False),('192.0.3.2',False)]:
 check('noncontiguous wildcard '+value,address_match(value,'192.0.2.0','0.0.0.254'),expected,dict(address=value,base='192.0.2.0',wildcard='0.0.0.254'))
# This ACL selects untrusted SSH for one hypothetical CoPP class with a drop action.
class_acl=[rule(10,'deny','tcp','192.0.2.10','0.0.0.0',dport=22),rule(20,'permit','tcp',dport=22)]
def classification(p):
 result=evaluate(class_acl,p)
 return dict(acl=result,selected=result['action']=='permit',classAction='drop' if result['action']=='permit' else 'not-selected')
for label,p,seq,action,selected in [('trusted SSH',packet(dport=22),10,'deny',False),('untrusted SSH',packet(src='203.0.113.8',dport=22),20,'permit',True),('unrelated HTTPS',flow,None,'deny',False)]:
 check('CoPP '+label,classification(p),dict(acl=dict(action=action,sequence=seq),selected=selected,classAction='drop'if selected else'not-selected'),dict(classAcl=class_acl,packet=p))
for label,outcomes,expected in [
 ('remote PASS stops',[('remote','PASS'),('local','PASS')],dict(result='PASS',visited=['remote'])),
 ('remote FAIL stops',[('remote','FAIL'),('local','PASS')],dict(result='FAIL',visited=['remote'])),
 ('remote ERROR permits local attempt',[('remote','ERROR'),('local','PASS')],dict(result='PASS',visited=['remote','local'])),
 ('local FAIL after remote ERROR denies',[('remote','ERROR'),('local','FAIL')],dict(result='FAIL',visited=['remote','local'])),
 ('all methods ERROR do not authenticate',[('remote','ERROR'),('local','ERROR')],dict(result='ERROR',visited=['remote','local']))]:check('AAA '+label,aaa(outcomes),expected,dict(outcomes=outcomes))
report=dict(checkedAt=datetime.datetime.now(datetime.timezone.utc).isoformat(),python=platform.python_version(),scriptSha256=hashlib.sha256(pathlib.Path(__file__).read_bytes()).hexdigest(),checks=checks,models=['ordered IPv4 ACL matcher','single CoPP class selector','AAA method outcome state machine'],limitations=['Teaching models, not Cisco IOS XE execution or packet-level acceptance','Only listed IPv4 fields and exact ports; no fragments, NAT order, IPv6, TCAM or complete CLI parser','CoPP class selection only; no rate, burst, CPU load, hardware queues or real policy-default verdict','AAA outcomes supplied as inputs; no server, protocol, credentials, timeout measurement or authorization implementation','No network, Docker, device changes or production service validation'])
pathlib.Path(sys.argv[1]).write_text(json.dumps(report,indent=2)+'\n');print(json.dumps(dict(checks=len(checks),models=len(report['models']),scriptSha256=report['scriptSha256'])))
NA PRÁTICA

remote=FAIL termina sem consultar local; remote=ERROR permite tentar local.

Armadilhas comuns

Usar rejeição como teste de fallback; confundir permit de classificação com aceitação; escolher taxas sem baseline; encerrar a única sessão antes de provar recuperação.

Tópicos relacionados: Observação e diagnóstico da rede · Segurança da infraestrutura e acesso ao equipamento

Leva esta ideia contigo

Interpreta cada decisão no seu contexto e mantém evidência do acesso normal, da negação e da recuperação.

Criar conta

Referência: Configuring Authentication · 350-401 ENCOR v1.2, effective 2026-03-19; core component of CCNP Enterprise

CCNP® e Cisco® são marcas registadas da Cisco Systems, Inc. e/ou das suas afiliadas. A dr.pt é uma plataforma de preparação independente e não está afiliada, associada, patrocinada, autorizada nem aprovada por Cisco. 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.