Eu finalmente resolvi o problema, mas o problema era impossível de ver pelo que eu publiquei. Eu destilei o script de dados do usuário em algo que eu poderia postar aqui, mas na verdade é muito mais longo. A parte principal não postada é que o aplicativo iniciado por este processo precisa de acesso ao SES da Amazon. Quando postei essa pergunta, essas variáveis de ambiente estavam no topo do script, e a chamada S3 estava usando-as e não a função atribuída. Depois que movi as variáveis de ambiente para um pouco antes de o aplicativo ser iniciado (importante, depois do comando de download do S3), o script de dados do usuário funcionava como esperado.
A parte importante que vale a pena capturar é que, embora a função do IAM seja atribuída à instância, e a AWS cli usará essas credenciais automaticamente, as credenciais são usadas da mesma forma que as credenciais do usuário para chamadas do S3. A definição de outras credenciais com certeza substituirá as da função. Antes de me deparar com esse problema, fiquei com a impressão de que o serviço S3 poderia ter uma maneira de validar o chamador e a função do chamador quando a solicitação é interna à AWS.